This occurs because there is only one i
variable in the original code as for
does not introduce a new variable "each loop" and the same variable is closed over in all the closures! As such, the same (i
) variable is assigned the last value (3) before any of the functions are executed after the loop.
Compare with the following code which ensures a new variable to bind in each closure (this is one rare case where I use underscores for a local variable to show "something funny" is happening):
for (int _i = 0; _i < tmp.Length; _i++)
{
int i = _i; // NEW/fresh variable, i, introduced each loop
tmp[i] = () => Console.WriteLine(i);
}
This behavior (and complaints against) is discussed in detail in Is there a reason for C#'s reuse of the variable in a foreach? - for
and foreach
have this same "issue" in C#4 and before, which is "fixed" for foreach
in C#5.
I think it is fair to say that all regret that decision. This is one of the worst "gotchas" in C#, and we are going to take the breaking change to fix it. In C# 5 the foreach loop variable will be logically inside the body of the loop, and therefore closures will get a fresh copy every time. - Eric Lippert