Closures behaving differently in for and foreach loops
Solution 1:
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.