Reading Anders’ post on Lexical Closures, Deferred Execution and Kicker Methods with respect to LINQ and Quaere, I thought I would write some notes since VS 2008 is RTM this month and I’ll hopefully get to start doing some more LINQing.
I have used Anders’ example. What result is printed?
int[] numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int i = 1;
var numbersPlusI = from n in numbers
select n + i;
i++;
foreach (var n in numbersPlusI) {
Console.Write(n);
Console.Write(" ");
}
To make the answer more obvious, let’s rewrite without the layer of syntactic sugar. As I don’t have .NET 3.5 handy on this PC, this is just an approximation built on .NET 2.0:
int[] numbers = new int[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int i = 1;
IEnumerable<int> numbersPlusI =
Enumerable.Select<int>(numbers, delegate(int n) { return n + i; } );
i++;
foreach (int n in numbersPlusI) {
Console.WriteLine(n);
Console.Write(" ");
}
LINQ builds up an expression for numbersPlusI, but doesn’t execute it until the result is enumerated. Now remembering that C# has closures, the delegate binds to the local variable i (not its value at the point of declaration). When the enumeration is being performed, the delegate is called using i, which is 2 at the time of execution (i=1; i++). So we get:
2 3 4 5 6 7 8 9 10 11
If you want to run the code on .NET 2.0, here is my approximation of System.Linq.Enumerable and the Func<> delegate relevant for the example. Probably not brilliant, but I am really aiming to illustrate how variables a captured by closures in C#.
public delegate T Func<T, A>(A a);
public class Enumerable {
public static IEnumerable<T> Select<T>(IEnumerable<T> source, Func<T,T> valueFromSource) {
foreach (T value in source) {
yield return valueFromSource(value);
}
}
}
Some good references on this: