430 likes | 1.07k Vues
Programming in C# Extension Methods. CSE 459.24 Prof . Roger Crawfis. Extension Methods. Can add methods to other classes Let me repeat that: Can add methods to other classes any methods (although they look static) only from static classes
E N D
Programming in C#Extension Methods CSE 459.24 Prof. Roger Crawfis
Extension Methods • Can add methods to other classes • Let me repeat that: Can add methods to other classes • any methods (although they lookstatic) • 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 publicstaticclassExtensions { publicstaticint ToInt32(thisstringintegerString) { returnInt32.Parse(integerString); } publicstatic T[] Slice<T>(this T[] source, intstartIndex, int count) { if(startIndex < 0 || count < 0 || (source.Length - startIndex) < count) thrownewInvalidArgumentException(); 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 method • Can only access public methods, etc. • Allows for chaining method calls. • More later when we talk about LINQ.
Extension Method Example publicstaticclassMyExtensions { publicstatic 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); yieldreturnsaveList.Dequeue(); } yieldbreak; } } http://blogs.msdn.com/ericwhite/archive/2008/11/14/the-skiplast-extension-method.aspx
Extension Method Example classProgram { staticvoid 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); } } 1 2 3 two three four
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 publicclassStudent{ publicstringfirstName; publicstringlastName; } publicclassScienceClass{ publicStudent Student1, Student2, Student3; } staticvoid Main(string[] args){ var student1 = newStudent { firstName = "Bruce", lastName = "Willis“ }; var student2 = newStudent { firstName = "George", lastName = "Clooney"}; var student3 = newStudent { firstName = "James", lastName = "Cameron“ }; varsClass = newScienceClass { Student1 = student1, Student2 = student2, Student3 = student3 }; }
Initializers Example // Using a Constructor Person p = newPerson("John", "Doe", "602-123-1234"); // Using Properties and an initializer Person p = newPerson() { FirstName="John", LastName="Doe", Phone="602-123-1234", City="Phoenix"}; // Adding a composite type Person p = newPerson() { 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. vari = 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 arrays • var 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 type • An anonymous type can not be referred to by name in a program. • Structural type equivalence • Two anonymous types can be compatible • Why in the world would we want these? • Again, needed/useful for LINQ.
Anonymous Types Example protectedobjectAnonymousTypes() { // *** 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 = rick@west-wind.com } }; 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) { returnperson.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
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 Anonymous Methods • Further simplification delegate void EventHandler (object sender, EventArgs arg); Button button = new Button(); Button.Click += delegate (objectsender, EventArgsarg) { Console.WriteLine("clicked"); };
dummy object 0 add delegate x++; return x; 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 • delegateintAdder(); • staticAdderCreateAdder() { • int x = 0; • returndelegate { x++; return x; }; • } • publicstaticvoid Main() { • Adder add = CreateAdder(); • Console.WriteLine(add()); • Console.WriteLine(add()); • Console.WriteLine(add()); • add = CreateAdder(); • Console.WriteLine(add()); • Console.WriteLine(add()); • Console.WriteLine(add()); • } 2 3 1 The dummy object lives as long as the delegate object 1 2 3 1 2 3 Output:
Anonymous Method Example delegatevoidMyDelegate(); classProgram { staticMyDelegateFoo() { 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 = 1 delegate: x = 2 delegate: x = 3 Foo: x = 3 second delegate: x = 13 delegate: x = 14 Foo: x = 14 second delegate: x = 24 --- Main: Foo()(); Foo: x = 1 delegate: x = 2 delegate: x = 3 Foo: x = 3 second delegate: x = 13 delegate: x = 14 Foo: x = 14 second delegate: x = 24 staticvoid 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(intx) { return x + 1;} • Can have implicitly typed variables • Can have more than one variable • Can 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 inference public static IEnumerable<S> Select<T,S>( thisIEnumerable<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 type Sequence.Select<Customer, S>(customers, c => c.Name) • c lambda expression argument type is inferred to Customer Sequence.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) publicstaticclassSequence { publicstatic IEnumerable<S> Select<T,S>(this IEnumerable<T> source, Func<T, S> selector) { foreach (T element in source) yieldreturn 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 type delegateR 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 code delegateR Func<A,R>(A arg); staticZ 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