
Pro CSharp 2008 And The .NET 3.5 Platform [eng]
.pdf
452 CHAPTER 14 ■ AN INTRODUCTION TO LINQ
■Note Many of the types that represent a LINQ result are hidden by the Visual Studio 2008 object browser. Make use of ildasm.exe or reflector.exe to see these internal, hidden types.
LINQ and Implicitly Typed Local Variables
While the current sample program makes it relatively easy to determine that the result set is enumerable as a string collection, I would guess that it is not clear that subset is really of type OrderedEnumerable<TElement, TKey>. Given the fact that LINQ result sets can be represented using a good number of types in various LINQ-centric namespaces, it would be tedious to define the proper type to hold a result set, because in many cases the underlying type may not be obvious or directly accessible from your code base (and as you will see, in some cases the type is generated at compile time).
To further accentuate this point, consider the following additional helper method defined within the Program class (which I assume you will invoke from within the Main() method):
static void QueryOverInts()
{
int[] numbers = {10, 20, 30, 40, 1, 2, 3, 8};
// Only print items less than 10.
IEnumerable<int> subset = from i in numbers where i < 10 select i;
foreach (int i in subset) Console.WriteLine("Item: {0}", i);
ReflectOverQueryResults(subset);
}
In this case, the subset variable is obtained (under the covers) by calling the System.Linq. Enumerable.Where<T> method, passing in a compiler-generated anonymous method as the second parameter. Here is the crux of the internal definition of the subset variable generated by the compiler (assume the anonymous method has been named 9__CachedAnonymousMethodDelegate8):
//The following LINQ query expression:
//IEnumerable<int> subset = from i in numbers where i < 10 select i;
//Is transformed into a call to the Enumerable.Where<int>() method:
IEnumerable<int> subset = Enumerable.Where<int>(numbers, Program.<>9__CachedAnonymousMethodDelegate8);
■Note I would recommend that you load LINQ-based applications into a decompiler such as ildasm.exe or reflector.exe. These sorts of tools can greatly strengthen your understanding of LINQ internals.
Without diving too deeply into the use of Enumerable.Where<T> at this point, do note that in Figure 14-3, the underlying type for each query expression is indeed unique, based on the format of our LINQ query expression.


454CHAPTER 14 ■ AN INTRODUCTION TO LINQ
background. LINQ query expressions can be used to iterate over data containers that implement the generic IEnumerable<T> interface. However, the .NET System.Array class type (used to represent our array of strings and array of integers) does not implement this behavior:
//The System.Array type does not seem to implement the correct
//infrastructure for query expressions!
public abstract class Array : ICloneable, IList, ICollection, IEnumerable
{
...
}
While System.Array does not directly implement the IEnumerable<T> interface, it indirectly gains the required functionality of this type (as well as many other LINQ-centric members) via the static System.Linq.Enumerable class type. This type defined a good number of generic extension methods (such as Aggregate<T>(), First<T>(), Max<T>(), etc.), which System.Array (and other types) acquire in the background. Thus, if you apply the dot operator on the currentVideoGames local variable, you will find a good number of members not found within the formal definition of System.Array (see Figure 14-4).
Figure 14-4. The System.Array type has been extended with members of System.Linq.Enumerable.
The Role of Differed Execution
Another important point regarding LINQ query expressions is that they are not actually evaluated until you iterate over their contents. Formally speaking, this is termed differed execution. The benefit of this approach is that you are able to apply the same LINQ query multiple times to the same container, and rest assured you are obtaining the latest and greatest results. Consider the following update to the QueryOverInts() method:
static void QueryOverInts()
{
int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 };


456 CHAPTER 14 ■ AN INTRODUCTION TO LINQ
The Role of Immediate Execution
When you wish to evaluate a LINQ expression from outside the confines of foreach logic, you are able to call any number of extension methods defined by the Enumerable type to do so. Enumerable defines a number of extension methods such as ToArray<T>(), ToDictionary<TSource,TKey>(), and ToList<T>(), which allow you to capture a LINQ query result set in a strongly typed container. Once you have done so, the container is no longer “connected” to the LINQ expression, and may be independently manipulated:
static void ImmediateExecution()
{
int[] numbers = { 10, 20, 30, 40, 1, 2, 3, 8 };
//Get data RIGHT NOW as int[]. int[] subsetAsIntArray =
(from i in numbers where i < 10 select i).ToArray<int>();
//Get data RIGHT NOW as List<int>.
List<int> subsetAsListOfInts =
(from i in numbers where i < 10 select i).ToList<int>();
}
Notice that the entire LINQ expression is wrapped within parentheses to cast it into the correct underlying type (whatever that may be) in order to call the extension methods of Enumerable.
Also recall from Chapter 10 that when the C# compiler can unambiguously determine the type parameter of a generic item, you are not required to specify the type parameter. Thus, we could also call ToArray<T>() (or ToList<T>() for that matter) as follows:
int[] subsetAsIntArray =
(from i in numbers where i < 10 select i).ToArray();
■Source Code The LinqOverArray project can be found under the Chapter 14 subdirectory.
LINQ and Generic Collections
Beyond pulling results from a simple array of data, LINQ query expressions can also manipulate data within members of the System.Collections.Generic namespace, such as the List<T> type. Create a new .NET 3.5 Console Application project named LinqOverCustomObjects, and define a basic Car type that maintains a current speed, color, make, and pet name (public fields are used to easily set the string fields to empty text. Feel free to make use of automatic properties and class constructors if you wish):
class Car
{
public string PetName = string.Empty; public string Color = string.Empty; public int Speed;
public string Make = string.Empty;
}
Now, within your Main() method, define a local List<T> variable of type Car, and make use of the new object initialization syntax (see Chapter 13) to fill the list with a handful of new Car objects:

CHAPTER 14 ■ AN INTRODUCTION TO LINQ |
457 |
static void Main(string[] args)
{
Console.WriteLine("***** More fun with LINQ Expressions *****\n");
//Make a List<> of Car objects
//using object init syntax.
List<Car> myCars = new List<Car>() {
new Car{ PetName = "Henry", Color = "Silver", Speed = 100, Make = "BMW"}, new Car{ PetName = "Daisy", Color = "Tan", Speed = 90, Make = "BMW"}, new Car{ PetName = "Mary", Color = "Black", Speed = 55, Make = "VW"}, new Car{ PetName = "Clunker", Color = "Rust", Speed = 5, Make = "Yugo"}, new Car{ PetName = "Melvin", Color = "White", Speed = 43, Make = "Ford"}
};
}
Applying a LINQ Expression
Our goal is to build a query expression to select only the items within the myCars list, where the speed is greater than 55. Once we get the subset, we will print out the name of each Car object. Assume you have the following helper method (taking a List<Car> parameter), which is called from within Main():
static void GetFastCars(List<Car> myCars)
{
// Create a query expression.
var fastCars = from c in myCars where c.Speed > 55 select c;
foreach (var car in fastCars)
{
Console.WriteLine("{0} is going too fast!", car.PetName);
}
}
Notice that our query expression is only grabbing items from the List<T> where the Speed property is greater than 55. If we run the application, we will find that “Henry” and “Daisy” are the only two items that match the search criteria.
If we want to build a more complex query, we might wish to only find the BMWs that have a Speed value above 90. To do so, simply build a compound Boolean statement using the C# && operator:
// Create a query expression.
var fastCars = from c in myCars where c.Speed > 90 && c.Make == "BMW" select c;
In this case, the only pet name printed out is “Henry”.
■Source Code The LinqOverCustomObjects project can be found under the Chapter 14 subdirectory.
LINQ and Nongeneric Collections
Recall that the query operators of LINQ are designed to work with any type implementing IEnumerable<T> (either directly or via extension methods). Given that System.Array has been

458CHAPTER 14 ■ AN INTRODUCTION TO LINQ
provided with such necessary infrastructure, it may surprise you that the legacy (nongeneric) containers within System.Collections have not. Thankfully, it is still possible to iterate over data contained within nongeneric collections using the generic Enumerable.OfType<T>() method.
The OfType<T>() method is one of the few members of Enumerable that does not extend generic types. When calling this member off a nongeneric container implementing the IEnumerable interface (such as the ArrayList), simply specify the type of item within the container to extract
a compatible IEnumerable<T> object. Assume we have a new Console Application named LinqOverArrayList that defines the following Main() method (note that we are making use of the previously defined Car type and be sure to import the System.Collections namespace).
static void Main(string[] args)
{
Console.WriteLine("***** LINQ over ArrayList *****\n");
//Here is a nongeneric collection of cars.
ArrayList myCars = new ArrayList() {
new Car{ PetName = "Henry", Color = "Silver", Speed = 100, Make = "BMW"}, new Car{ PetName = "Daisy", Color = "Tan", Speed = 90, Make = "BMW"}, new Car{ PetName = "Mary", Color = "Black", Speed = 55, Make = "VW"}, new Car{ PetName = "Clunker", Color = "Rust", Speed = 5, Make = "Yugo"}, new Car{ PetName = "Melvin", Color = "White", Speed = 43, Make = "Ford"}
};
//Transform ArrayList into an IEnumerable<T>-compatible type.
IEnumerable<Car> myCarsEnum = myCars.OfType<Car>();
//Create a query expression.
var fastCars = from c in myCarsEnum where c.Speed > 55 select c;
foreach (var car in fastCars)
{
Console.WriteLine("{0} is going too fast!", car.PetName);
}
}
Filtering Data Using OfType<T>()
As you know, nongeneric types are capable of containing any combination of items, as the members of these containers (again, such as the ArrayList) are prototyped to receive System.Objects. For example, assume an ArrayList contains a variety of items, only a subset of which are numerical. If we want to obtain a subset that contains only numerical data, we can do so using OfType<T>(), since it filters out each element whose type is different from the given type during the iterations:
//Extract the ints from the ArrayList.
ArrayList myStuff = new ArrayList();
myStuff.AddRange(new object[] { 10, 400, 8, false, new Car(), "string data" }); IEnumerable<int> myInts = myStuff.OfType<int>();
//Prints out 10, 400, and 8.
foreach (int i in myInts)
{
Console.WriteLine("Int value: {0}", i);
}

CHAPTER 14 ■ AN INTRODUCTION TO LINQ |
459 |
■Source Code The LinqOverArrayList project can be found under the Chapter 14 subdirectory.
Now that you have seen how to use LINQ to manipulate data contained within various arrays and collections, let’s dig in a bit deeper to see what is happening behind the scenes.
The Internal Representation of LINQ Query
Operators
So at this point you have been briefly introduced to the process of building query expressions using various C# query operators (such as from, in, where, orderby, and select). When compiled, the C# compiler actually translates these tokens into calls on various methods of the System.Linq. Enumerable type (and possibly other types, based on your LINQ query).
As it turns out, a great many of the methods of Enumerable have been prototyped to take delegates as arguments. In particular, many methods require a generic delegate of type Func<>, defined within the System namespace of System.Core.dll. For example, consider the following members of
Enumerable that extend the IEnumerable<T> interface:
//Overloaded versions of the Enumerable.Where<T>() method.
//Note the second parameter is of type System.Func<>.
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
System.Func<TSource,int,bool> predicate)
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
System.Func<TSource,bool> predicate)
This delegate (as the name implies) represents a pattern for a given function with a set of arguments and a return value. If you were to examine this type using the Visual Studio 2008 object browser, you’ll notice that the Func<> delegate can take between zero and four input arguments (here typed T0, T1, T2, and T3 and named arg0, arg1, arg2, and arg3), and a return type denoted by
TResult:
// The various formats of the Func<> delegate. public delegate TResult Func<T0,T1,T2,T3,TResult>(
T0 arg0, T1 arg1, T2 arg2, T3 arg3)
public delegate TResult Func<T0,T1,T2,TResult>(T0 arg0, T1 arg1, T2 arg2) public delegate TResult Func<T0,T1,TResult>(T0 arg0, T1 arg1)
public delegate TResult Func<T0,TResult>(T0 arg0) public delegate TResult Func<TResult>()
Given that many members of System.Linq.Enumerable demand a delegate as input, when invoking them, we 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

460CHAPTER 14 ■ AN INTRODUCTION TO LINQ
illustrate the various manners in which we can build LINQ query expressions. The first method, QueryStringsWithOperators(), offers the most straightforward way to build a query expression and is identical to the code seen in the previous LinqOverArray example:
static void QueryStringWithOperators()
{
Console.WriteLine("***** Using Query Operators *****");
string[] currentVideoGames = {"Morrowind", "BioShock", "Half Life 2: Episode 1", "The Darkness",
"Daxter", "System Shock 2"};
//Build a query expression using query operators. var subset = from g in currentVideoGames
where g.Length > 6 orderby g select g;
//Print out the results.
foreach (var s in subset) Console.WriteLine("Item: {0}", s);
}
The obvious benefit of using C# query operators to build query expressions is the fact that the Func<> delegates and calls on the Enumerable type are out of sight and out of mind, as it is the job of the C# compiler to perform this translation. To be sure, building LINQ expressions using various query operators (from, in, where, orderby, etc.) is the most common and most straightforward approach.
Building Query Expressions Using the Enumerable Type
and Lambdas
Keep in mind that the LINQ query operators used here are simply shorthand versions for calling various extension methods defined by the Enumerable type. Consider the following QueryStringsWithEnumerableAndLambdas() method, which is processing the local string array now making direct use of the Enumerable extension methods:
static void QueryStringsWithEnumerableAndLambdas()
{
Console.WriteLine("***** Using Enumerable / Lambda Expressions *****");
string[] currentVideoGames = {"Morrowind", "BioShock", "Half Life 2: Episode 1", "The Darkness",
"Daxter", "System Shock 2"};
//Build a query expression using extension methods
//granted to the Array via the Enumerable type.
var subset = currentVideoGames.Where(game => game.Length > 6)
.OrderBy(game => game).Select(game => game);
// Print out the results. foreach (var game in subset)
Console.WriteLine("Item: {0}", game); Console.WriteLine();
}
Here, we are calling the generic Where() method off the string array object, granted to the Array type as an extension method defined by Enumerable. The Enumerable.Where<T>() method makes use of the System.Func<T0, TResult> delegate type. The first type parameter of this delegate represents

CHAPTER 14 ■ AN INTRODUCTION TO LINQ |
461 |
the IEnumerable<T>-compatible data to process (an array of strings in this case), while the second type parameter represents the method that will process said data.
Given that we have opted for a lambda expression (rather than directly creating an instance of Func<T> or crafting an anonymous method), we are specifying that the “game” parameter is processed by the statement game.Length > 6, which results in a Boolean return type.
The return value of the Where<T>() method has implicitly typed, but under the covers we are operating on an OrderedEnumerable type. From this resulting object, we call the generic OrderBy<T, K>() method, which also requires a Func<T, K> delegate parameter. Finally, from the result of the specified lambda expression, we select each element, using once again a Func<T, K> under the covers.
It is also worth remembering that extension methods are unique in that they can be called as instance-level members upon the type they are extending (System.Array in this case) or as static members using the type they were defined within. Given this, we could also author our query expression as follows:
var subset = Enumerable.Where(currentVideoGames, game => game.Length > 6)
.OrderBy(game => game).Select(game => game);
As you may agree, building a LINQ query expression using the methods of the Enumerable type directly is much more verbose than making use of the C# query operators. As well, given that the methods of Enumerable require delegates as parameters, you will typically need to author lambda expressions to allow the input data to be processed by the underlying delegate target.
Building Query Expressions Using the Enumerable Type and
Anonymous Methods
Given that C# 2008 lambda expressions are simply shorthand notations for working with anonymous methods, consider the third query expression created within the
QueryStringsWithAnonymousMethods() helper function:
static void QueryStringsWithAnonymousMethods()
{
Console.WriteLine("***** Using Anonymous Methods *****");
string[] currentVideoGames = {"Morrowind", "BioShock", "Half Life 2: Episode 1", "The Darkness",
"Daxter", "System Shock 2"};
//Build the necessary Func<> delegates using anonymous methods.
Func<string, bool> searchFilter =
delegate(string game) { return game.Length > 6; };
Func<string, string> itemToProcess = delegate(string s) { return s; };
//Pass the delegates into the methods of Enumerable.
var subset = currentVideoGames.Where(searchFilter)
.OrderBy(itemToProcess).Select(itemToProcess);
// Print out the results. foreach (var game in subset)
Console.WriteLine("Item: {0}", game); Console.WriteLine();
}
This iteration of the query expression is even more verbose, because we are manually creating the Func<> delegates used by the Where(), OrderBy(), and Select() methods of the Enumerable type.