Warning when accessing a modified closure in lambda expression
If you use lambda expressions there is a little know warning when you use a variable inside the lambda that is updated outside
What is the output of this code that write 0 to 4 but adding the actions to the list:
var actions = new List<Action>();
for (int i = 0; i < 5; i++)
actions.Add(() => Console.WriteLine(i));
foreach (var action in actions)
action();
The real output of this code is:
5
5
5
5
5
That is expected and not is a problem in the compiler or framework, the problem is that the compiler generates a method that use the i variable and when the loops finish the i variable has the value 5
Solution
Copy to a local variable of the loop and use it:
for (int i = 0; i < 5; i++)
{
var i2 = i;
actions.Add(() => Console.WriteLine(i2));
}
Now the compiler generated method is using i2 variable, and there are 5 variables with the right value
Suggestion
If you use Resharper, it auto detects this problem but just a warning, you can change it to Error to get an advise when you fall in this problem:
Resharper suggest the solution
PS: If you use C# 5 MS already introduced the fix (that is in fact a breaking change), from 5 and forward the loops always get the current value in the iteration and not a reference to the variable itself.
More Info: http://visualstudiomagazine.com/Articles/2012/11/01/More-Than-Just-Async.aspx?Page=1