Skip to content

Foreach variable capture fix C# 5.0correctness

Each iteration of `foreach` now captures its own copy of the loop variable.

In C# 4.0 and earlier the foreach loop reused the same variable for each iteration. This meant that closures (such as lambda expressions or delegates) created inside the loop all captured the same variable and would see its final value rather than the value at the time they were created.

This was a very common source of bugs, especially when creating tasks, event handlers, or LINQ queries inside a loop.

C# 5.0 changed the behavior so that each iteration of foreach gets its own copy of the loop variable, making closure capture work as most developers expect.

Code

C#
var actions = new List<Action>();
foreach (var name in new[] { "Alice", "Bob", "Charlie" })
    actions.Add(() => Console.WriteLine(name));

foreach (var action in actions)
    action();
// Output: Alice, Bob, Charlie
C#
var actions = new List<Action>();
foreach (var name in new[] { "Alice", "Bob", "Charlie" })
    actions.Add(() => Console.WriteLine(name));

foreach (var action in actions)
    action();
// Output: Charlie, Charlie, Charlie (all captured the same variable)

Notes

  • This was a breaking change but was considered acceptable because the old behavior was almost never intentional
  • The for loop was not changed - for (int i = ...) still reuses the same variable, so closure capture in for loops still requires a local copy
  • Eric Lippert described the original behavior as "the single most common incorrect bug report" for the C# compiler

More information