Closures behaving differently in for and foreach loops

In C# 5 and beyond, the foreach loop declares a separate i variable for each iteration of the loop. So each closure captures a separate variable, and you see the expected results.

In the for loop, you only have a single i variable, which is captured by all the closures, and modified as the loop progresses – so by the time you call the delegates, you see the final value of that single variable.

In C# 2, 3 and 4, the foreach loop behaved that way as well, which was basically never the desired behaviour, so it was fixed in C# 5.

You can achieve the same effect in the for loop if you introduce a new variable within the scope of the loop body:

for (int i = 3; i <= 4; i++)
{
    int copy = i;
    actions.Add(() => Console.WriteLine(copy));
}

For more details, read Eric Lippert’s blog posts, “Closing over the loop variable considered harmful” – part 1, part 2.

Leave a Comment