Sunday, May 17, 2009

Variable capture in C# closures

You have to be careful about variable capture when constructing lambdas in C#.  The following code does not do what you might imagine:

var xs = new List<Action>();
for(var x = 0; x < 10; x++) {
xs.Add(() => {Console.Write(x + " ");});
};
foreach (var a in xs) {
a();
}

This prints the following: 10 10 10 10 10 10 10 10 10 10
The reason is that the variable x is captured by the lambdas, not the value of x at the time the lambda is created.

To avoid this situation we have to make a local copy of x for each lambda:

var xs = new List<Action>();
for(var x = 0; x < 10; x++) {
var x_copy = x;
xs.Add(() => {Console.Write(x_copy + " ");});
};
foreach (var a in xs) {
a();
}

This prints 0 1 2 3 4 5 6 7 8 9 as expected.

No comments: