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: