Programming in C# Extension Methods
CSE 459.24Prof. Roger Crawfis
Extension Methods
Can add methods to other classesLet me repeat that: Can add methods to
other classes any methods (although they look static) only from static classes
When you import a namespace that has extensions, these are added to classes once imported, called as usual instance methods
Local methods take precedence
Extension Methods
public static class Extensions {
public static int ToInt32(this string integerString)
{
return Int32.Parse(integerString);
}
public static T[] Slice<T>(this T[] source, int startIndex, int count)
{
if (startIndex < 0 || count < 0 || (source.Length - startIndex) < count)
throw new InvalidArgumentException();
T[] result = new T[count];
Array.Copy(source, startIndex, result, 0, count);
return result;
}
}
Extension Methods
Properties, events and operators can not have extension methods.
Equivalent to calling the static methodCan only access public methods, etc.
Allows for chaining method calls.More later when we talk about LINQ.
Extension Method Example
public static class MyExtensions {
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int count) {
Queue<T> saveList = new Queue<T>();
int saved = 0;
foreach (T item in source) {
if (saved < count) {
saveList.Enqueue(item);
++saved;
continue;
}
saveList.Enqueue(item);
yield return saveList.Dequeue();
}
yield break;
}
}
http://blogs.msdn.com/ericwhite/archive/2008/11/14/the-skiplast-extension-method.aspx
Extension Method Example
class Program {
static void Main(string[] args) {
int[] a = new[] { 1, 2, 3, 4, 5 };
var b = a.SkipLast(2);
foreach (var item in b)
Console.WriteLine(item);
var c = new List<string>() { "one", "two", "three", "four", "five" };
var d = c.Skip(1).SkipLast(1);
foreach (var e in d)
Console.WriteLine(e);
}
}
123twothreefour
Programming in C#Extension Methods
CSE 494R(proposed course for 459 Programming in C#)
Prof. Roger Crawfis
Programming in C# Types - Misc
CSE 494R(proposed course for 459 Programming in C#)
Prof. Roger Crawfis
Initializers
We already know how to initialize basic types:int index = 0;
string message = “Save the Cheerleader”;
And complex types using constructors:Person paul = new Person(“Paul”, “Newman”);
IList<string> words = new List<string>(35);
Can also use initializers to set properties and initialize collections.
Initializers
Can initialize fields or properties. new C(1, 2) {Name=“my class”}; Works if public field or a property with public set Point a = new Point { X = 0, Y = 1 }; Can be nested (eg. Rectangle with two Points)
Collection initializers List<int> digits = new List<int> { 0, 1}; Must implement System.Generic.ICollection<T>
Initializers Example
public class Student{
public string firstName;
public string lastName;
}
public class ScienceClass{
public Student Student1, Student2, Student3;
}
static void Main(string[] args){
var student1 = new Student { firstName = "Bruce", lastName = "Willis“ };
var student2 = new Student { firstName = "George", lastName = "Clooney"};
var student3 = new Student { firstName = "James", lastName = "Cameron“ };
var sClass = new ScienceClass { Student1 = student1, Student2 = student2, Student3 = student3 };
}
Initializers Example
// Using a Constructor
Person p = new Person("John", "Doe", "602-123-1234");
// Using Properties and an initializer
Person p = new Person() { FirstName="John", LastName="Doe", Phone="602-123-1234", City="Phoenix"};
// Adding a composite type
Person p = new Person() {
FirstName = "John",
LastName = "Doe",
Address = new Address() {
Street = "1234 St.",
City = "Phoenix“
}
};
Implicitly Typed Variables
Type of the variable induced from expression Must include an initializer Can not be null.
var i = 5;
var s = "Hello";
var d = 1.0; // Did you really mean a double?
var orders = new Dictionary<int,Order>();
var a = new Point { X = 0, Y = 1 };
Implicitly Typed Variables
Implicitly typed arraysvar a = new[ ] { 1, 10, 100, 1000 }; Must have consistent types or have implicit
conversions
Anonymous Types
var x = new {p1 = 10, p2 = “name”};x is an anonymous typeAn anonymous type can not be referred to
by name in a program.Structural type equivalence
Two anonymous types can be compatibleWhy in the world would we want these?
Again, needed/useful for LINQ.
Anonymous Types Example
protected object AnonymousTypes() {
// *** Create Complex Types 'on the fly‘
var Customer = new {
Company = "West Wind",
Name = "Rick",
Entered = DateTime.Now,
BillRate = 150M,
Contacts = new {
Phone = "808 121-1211",
Fax = "808 231-1211",
Email = [email protected]
}
};
return Customer;
}http://www.west-wind.com/weblog/posts/189329.aspx
Programming in C# Types - Misc
CSE 494R(proposed course for 459 Programming in C#)
Prof. Roger Crawfis
Programming in C#Anonymous Methods
CSE 494R(proposed course for 459 Programming in C#)
Prof. Roger Crawfis
Anonymous Method Example
Becomes quite cumbersome to create little methods for each specialization. These methods are only used in one context.
The use and declaration are disjoint. Would be nice to have the declaration in-line.
personList.RemoveAll( delegate(Person person) {
return person.DateOfBirth.Year < 1980;
});
Anonymous Methods
Delegates are clumsy: programmer has to name the function and “closure-convert” by hand
C# 2.0 introduced anonymous methods No name Compiler does closure-conversion, creating a class and object that
captures the environment e.g.
bool b = xs.Exists(delegate(int x) { return x > y; });
Local y is free in body of anonymous method
Anonymous Methods
Further simplification
Button button = new Button();Button.Click += delegate (object sender, EventArgs arg) { Console.WriteLine("clicked"); };
Can be simplified as follows
Button.Click += delegate { Console.WriteLine("clicked"); };
Formal parameters can be omitted if they are not used in the method body
delegate void EventHandler (object sender, EventArgs arg);
Outer Variables
If anonymous methods access variables of the enclosing method, these variables are evacuated into a dummy object (capturing)
The anonymous method and the enclosing method itself are then using a single evacuated variable
delegate int Adder();static Adder CreateAdder() {
int x = 0;return delegate { x++; return x; };}public static void Main() {Adder add = CreateAdder();Console.WriteLine(add());Console.WriteLine(add());Console.WriteLine(add());add = CreateAdder();Console.WriteLine(add());Console.WriteLine(add());Console.WriteLine(add());}
123123
Output:
x++; return x;
0dummy object
delegate
add123
The dummy object lives as long as the delegate object
Anonymous Method Example
delegate void MyDelegate();
class Program {
static MyDelegate Foo() {
int x = 1;
Console.WriteLine("Foo: x = {0}", x);
MyDelegate d = delegate { x++; Console.WriteLine("delegate: x = {0}", x); };
d(); d();
Console.WriteLine("Foo: x = {0}", x);
MyDelegate d2 = delegate { x += 10; Console.WriteLine("second delegate: x = {0}", x); };
d2(); d();
Console.WriteLine("Foo: x = {0}", x);
return d2;
}
--- Main: Foo()();Foo: x = 1delegate: x = 2delegate: x = 3Foo: x = 3second delegate: x = 13delegate: x = 14Foo: x = 14second delegate: x = 24--- Main: Foo()();Foo: x = 1delegate: x = 2delegate: x = 3Foo: x = 3second delegate: x = 13delegate: x = 14Foo: x = 14second delegate: x = 24
static void Main(string[] args) { Console.WriteLine("--- Main: Foo()();"); Foo()(); Console.WriteLine("--- Main: Foo()();"); Foo()(); }}
Programming in C#Anonymous Methods
CSE 494R(proposed course for 459 Programming in C#)
Prof. Roger Crawfis
Programming in C#Lambda Expressions
CSE 494R(proposed course for 459 Programming in C#)
Prof. Roger Crawfis
Lambda Expressions
Generalized function syntax x . x + 1 in C# 3.0, have x => x + 1
From anonymous delegate syntax:delegate(int x) { return x + 1;}
Can have implicitly typed variablesCan have more than one variableCan have expression or statement body
Lambda Expressions
Expression or statement body Implicitly or explicitly typed parameters Examples: x => x + 1 // Implicitly typed, expression body x => { return x + 1; } // Implicitly typed, statement body (int x) => x + 1 // Explicitly typed, expression body (int x) => { return x + 1; } // Explicitly typed, statement body (x, y) => x * y // Multiple parameters () => Console.WriteLine() // No parameters personList.RemoveAll(p => p.DateOfBirth.Year < 1980);
Lambda Expressions
Lambda expressions participate in inference process of type arguments of generic methods
In initial phase, nothing is inferred from arguments that are lambda expressions
Following the initial phase, additional inferences are made from lambda expressions using an iterative process
Lambda Expressions
Type inferencepublic static IEnumerable<S> Select<T,S>( this
IEnumerable<T> source, Func<T,S> selector)
{
foreach (T element in source)
yield return selector(element);
}
If call Select(customers, c => c.Name);T, S mapped to appropriate types
Lambda Expressions
Generic extension method example:
Calling extension method with lambda expression:List<Customer> customers = GetCustomerList();IEnumerable<string> names = customers.Select(c => c.Name);
Rewriting extension method call:IEnumerable<string> names = Sequence.Select<T, S>(customers, c => c.Name);
T type argument is inferred to Customer based on source argument typeSequence.Select<Customer, S>(customers, c => c.Name)
c lambda expression argument type is inferred to CustomerSequence.Select<Customer, S>(customers, (Customer c) => c.Name)
S type argument is inferred to string based on return value type of the lambda expression
Sequence.Select<Customer, string>(customers, (Customer c) => c.Name)
public static class Sequence { public static IEnumerable<S> Select<T,S>(this IEnumerable<T> source, Func<T, S> selector) { foreach (T element in source) yield return selector(element); } }
Lambda Expressions
A lambda expression is a value, that does not have a type but can be implicitly converted to a compatible delegate typedelegate R Func<A,R>(A arg);
Func<int,int> f1 = x => x + 1;
Func<int,double> f2 = x => x + 1;
Func<double,int> f3 = x => x + 1; // Error double -> int
Lambda Expressions
Given the codedelegate R Func<A,R>(A arg);
static Z F<X,Y,Z>(X x, Func<X,Y> f1, Func<Y,Z> f2)
{
return f2(f1(x));
}
What does the following produce?F("1:15:30", s => TimeSpan.Parse(s), t => t.TotalSeconds)
Extension Methods, …
Try this at home! Let’s wrap this discussion up by combining extension methods, implicit types, anonymous types and lambda expressions to create a complex process chain:
var processes =
System.Diagnostics.Process.GetProcesses()
.Where(proc => proc.WorkingSet64 > 20 * 1024 * 1024)
.OrderByDescending(proc => proc.WorkingSet64)
.Select(proc =>
new { Identifier = proc.Id, Name = proc.ProcessName });
foreach (var process in processes)Console.WriteLine("Identifier = {0}, Name = {1}", process.Identifier, process.Name);
Programming in C# Lambda Expressions
CSE 494R(proposed course for 459 Programming in C#)
Prof. Roger Crawfis