Preview of C# 3.0 • Query Expressions • Lambda Expressions • Extension Methods • Anonymous Types
© University of Linz, Institute for System Software, 2004 published under the Microsoft Curriculum License
Query Expressions SQL-like queries on arbitrary collections (IEnumerable) Sample collection string[] cities = {"London", "Vienna", "Paris", "Linz", "Brussels"};
Query IEnumerable<string> result = from c in cities select c;
Result
IEnumerable<string> result = from c in cities where c.StartsWith("L") orderby c select c.ToUpper();
foreach (string s in result) Console.WriteLine(s); London Vienna Paris Linz Brussels
LINZ LONDON
Query expressions are translated into lambda expressions and extension methods 2
Lambda Expressions Short form for delegate values delegate int Function(int x);
int Square(int x) { return x * x; } int Inc(int x) { return x + 1; }
C# 1.0 Function f; f = new Function(Square); f = new Function(Inc);
... f(3) ... ... f(3) ...
// 9 // 4
... f(3) ... ... f(3) ...
// 9 // 4
... f(3) ... ... f(3) ...
// 9 // 4
C# 2.0 f = delegate (int x) { return x * x; } f = delegate (int x) { return x + 1; }
C# 3.0 f = x => x * x; f = x => x + 1;
3
Example for Lambda Expressions Applying a function to a sequence of integers int[] Apply (Function f, int[] data) { int[] result = new int[data.Length]; for (int i = 0; i < data.Length; i++) { result[i] = f(data[i]); } return result; }
delegate int Function (int x);
int[] values = Apply ( i => 2 * i + 1 , new int[] {2, 4, 6, 8}); => 5, 9, 13, 17
4
Extension Methods Add functionality to an existing class Existing class Fraction class Fraction { public int z, n; public Fraction (int z, int n) {...} ... }
Usage Fraction f = new Fraction(1, 2); f = f.Inverse(); // f = FractionUtils.Inverse(f); f.Add(2); // FractionUtils.Add(f, 2);
Extension methods for class Fraction static class FractionUtils { public static Fraction Inverse (this Fraction f) { return new Fraction(f.n, f.z); } public static void Add (this Fraction f, int x) { f.z += x * f.n; } }
• must be declared in a static class • must be static methods • first parameter must be declared with this and must denote the class, to which the method should be added
• Can be called like instance methods of Fraction • However, can only access public members of Fraction
5
Example System.Query.Sequence has predeclared extension methods for IEnumerable namespace System.Query {
delegate bool Function (T x);
public static class Sequence { public static IEnumerable Where (this IEnumerable source, Function f) { ... returns all values x from source, for which f(x) == true ... } ... } }
Usage
makes Where visible
using System.Query; ... List list = ... list of integer values ...; IEnumerable result = list.Where(i => i > 0); Sequence.Where(list, i => i > 0) 6
Anonymous Types For creating structured values of an anonymous (i.e. nameless) type var obj = new { Name = "John", Id = 100 };
creates an object of a new type with the fields Name and Id for declaring variables of an anonymous type
class ??? { public string Name; public int Id; } ??? obj = new ???(); obj.Name = "John"; obj.Id = 100;
Even simpler, if the values are composed from fields of existing objects class Person { public string Name; public string Address; public int Id; } ... Person p = new Person(...), var obj = new { p.Name, p.Id };
anonymous type with fields Name and Id
7
Translation of Query Expressions Example: assume the following declarations List customers = ...;
class Customer { public string Name; public string City; public int Phone; }
Translation var result = from c in customers where c.City == "Vienna" orderby c.Name select new {c.Name, c.Phone}; foreach (var c in result) Console.WriteLine(c.Name + " " + c.Phone);
lambda expressions var result = customers .Where( c => c.City == "Vienna" ) .OrderBy( c=> c.Name ) .Select( c => new {c.Name, c.Phone} );
extension methods
anonymous type 8