The following code outputs 33 instead of 012. I don't understand why a new variable loopScopedi isn't captured in each iteration rather than capturing the same variable.
Action[] actions = new Action[3];
for (int i = 0; i < 3; i++)
{
actions [i] = () => {int loopScopedi = i; Console.Write (loopScopedi);};
}
foreach (Action a in actions) a(); // 333
Hopwever, this code produces 012. What's the difference between the two?
Action[] actions = new Action[3];
for (int i = 0; i < 3; i++)
{
int loopScopedi = i;
actions [i] = () => Console.Write (loopScopedi);
}
foreach (Action a in actions) a(); // 012
This is called "access to a modified closure". Basically, there is only one i
variable, and all three lambdas are referring to it. At the end, the one i
variable has been incremented to 3
, so all three actions print 3
. (Note that int loopScopedi = i
in the lambda only runs once you call the lambda later.)
In the second version, you are creating a new int loopScopedi
for every iteration, and setting it to the current value of i
, which is 0
and 1
and 2
, for each iteration.
You can try imagining inlining the lambdas to see more clearly what is happening:
foreach (Action a in actions)
{
int loopScopedi = i; // i == 3, since this is after the for loop
Console.Write(loopScopedi); // always outputs 3
}
Versus:
foreach (Action a in actions)
{
// normally you could not refer to loopScopedi here, but the lambda lets you
// you have "captured" a reference to the loopScopedi variables in the lambda
// there are three loopScopedis that each saved a different value of i
// at the time that it was allocated
Console.Write(loopScopedi); // outputs 0, 1, 2
}
Variables captured in a lambda are hoisted into a class shared between the lambda and the outside code.
In your first example, i
is being hoisted once and used with both the for()
and all the passed lambdas. By the time you reach Console.WriteLine
, the i
has reached 3
from the for()
loop.
In your second example, A new loopScopedi
is being hoisted for each run of the loop, so it is left unaffected by the subsequent loops.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With