Back to results for “OOP”
C# › Delegates, Events & Lambdas

How does variable capture (closures) work in a C# lambda expression, and what pitfall occurs when capturing a loop variable?

Intermediate

Answer

A lambda captures OUTER variables by REFERENCE (not by value at creation time), meaning it sees whatever the variable's value is at the moment the lambda actually EXECUTES — with modern C# (5.0+), each 'foreach' iteration variable is a fresh variable, avoiding the classic capture bug, but a 'for' loop's shared counter variable can still be captured unexpectedly if not handled carefully.
var actions = new List<Action>();
for (int i = 0; i < 3; i++) {
  int captured = i; // must copy into a NEW local to capture correctly in a 'for' loop
  actions.Add(() => Console.WriteLine(captured));
}
foreach (var action in actions) action(); // 0, 1, 2 (correct, thanks to the local copy)
Real-world example Debugging a classic closure bug where all queued callbacks unexpectedly print the SAME final loop value instead of their individually intended value.

Common follow-ups: Does this same capture pitfall still apply to C#'s modern 'foreach' loops, or only to 'for' loops?