Free mag vol1 | Page 526

CHAPTER 12  LINQ TO OBJECTS The Internal Representation of LINQ Query Statements At this point, you have been introduced to the process of building query expressions using various C# query operators (such as from, in, where, orderby, and select). Also, you discovered that some functionality of the LINQ to Objects API can only be accessed when calling ext ension methods of the Enumerable class. The truth of the matter, however, is that when compiled, the C# compiler actually translates all C# LINQ operators into calls on methods of the Enumerable class. In fact, if you were really a glutton for punishment, you could build all of your LINQ statements using nothing but the underlying object model. A great many of the methods of Enumerable have been prototyped to take delegates as arguments. In particular, many methods require a generic delegate named Func<>, which was introduced to you during our examination of generic delegates in Chapter 9. Consider the Where() method of Enumerable, which is called on your behalf when you use the C# where LINQ query operator: // Overloaded versions of the Enumerable.Where() method. // Note the second parameter is of type System.Func<>. public static IEnumerable Where(this IEnumerable source, System.Func predicate) public static IEnumerable Where(this IEnumerable source, System.Func predicate) The Func<> delegate (as the name implies) represents a pattern for a given function with a set of up to 16 arguments and a return value. If you were to examine this type using the Visual Studio object browser, you would notice various forms of the Func<> delegate. For example: // The various formats of the Func<> delegate. public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4) public delegate TResult Func(T1 arg1, T2 arg2, T3 arg3) public delegate TResult Func(T1 arg1, T2 arg2) public delegate TResult Func(T1 arg1) public delegate TResult Func() Given that many members of System.Linq.Enumerable demand a delegate as input, when invoking them, you can either manually create a new delegate type and author the necessary target methods, make use of a C# anonymous method, or define a proper lambda expression. Regardless of which approach you take, the end result is identical. While it is true that making use of C# LINQ query operators is far and away the simplest way to build a LINQ query expression, let’s walk through each of these possible approaches, just so you can see the connection between the C# query operators and the underlying Enumerable type. Building Query Expressions with Query Operators (Revisited) To begin, create a new Console Application named LinqUsingEnumerable. The Program class will define a series of static helper methods (each of which is called within the Main() method) to illustrate the various manners in which you can build LINQ query expressions. 466