Last Updated: September 09, 2019
·
3.382K
· marcosmeli

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:

Picture

Resharper suggest the solution

Picture

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