Closures and the loop variable trap

A lambda captures the variable, not the value it had at that moment. In a for loop that surprises almost everyone once.

Time O(n)Space O(n)Code C#
Watch it animatedStep through it, with the running line highlighted. Free with an account.

The idea

A for loop has one variable i for the whole loop. All three lambdas share it, and by the time they run the loop has finished with i = 3. Declaring a variable inside the body gives each lambda its own.

Code

var actions = new List<Action>();
for (int i = 0; i < 3; i++)
    actions.Add(() => Console.Write(i));   // captures the variable i
foreach (var act in actions) act();        // prints 333

var fixedActions = new List<Action>();
for (int i = 0; i < 3; i++) {
    int copy = i;                          // a fresh variable each time
    fixedActions.Add(() => Console.Write(copy));
}
foreach (var act in fixedActions) act();   // prints 012

Tips

In the .NET library

The same rule explains why a lambda passed to Task.Run sees later changes to a captured local. Copy the value to a new local first if you need a snapshot.