340 likes | 446 Vues
This guide delves into C# extension methods, a powerful feature that allows developers to add new methods to existing classes without modifying their source code. Learn how to create and use extension methods effectively, including examples for parsing strings to integers and manipulating arrays. Understand the limitations, such as the inability to add properties or events, and how extension methods facilitate method chaining. This tutorial also touches on the importance of using proper namespaces for accessibility. Uncover how extension methods can streamline your coding practices in C#.
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