Take the 2-minute tour ×

Consider this code.

        var values = new List<int> {123, 432, 768};

        var funcs = new List<Func<int>>();


        funcs.ForEach(f=>Console.WriteLine(f()));//prints 123,432,768


        foreach (var v1 in values)

        foreach (var func in funcs)
            Console.WriteLine(func());  //prints 768,768,768

I know that the second foreach prints 768 3 times because of the closure variable captured by the lambda. why does it not happen in the first case?How does foreach keyword different from the method Foreach? Is it beacuse the expression is evaluated when i do values.ForEach

share|improve this question

2 Answers 2

up vote 9 down vote accepted

foreach only introduces one variable. While the lambda parameter variable is "fresh" each time it is invoked.

Compare with:

foreach (var v1 in values) // v1 *same* variable each loop, value changed
   var freshV1 = v1; // freshV1 is *new* variable each loop
   funcs.Add(() => freshV1);

foreach (var func in funcs)
   Console.WriteLine(func()); //prints 123,432,768

That is,

foreach (T v in ...) { }

can be thought of as:

T v;
foreach(v in ...) {}

Happy coding.

share|improve this answer
Thanks. +1 for the write up. –  Ashley John Aug 20 '11 at 18:53

The difference is that in the foreach loop, you've got a single variable v1 which is captured. That variable takes on each value within values - but you're only using it at the end... which means we only see the final value each time.

In your List<T>.ForEach version, each iteration introduces a new variable (the parameter f) - so each lambda expression is capturing a separate variable, which never changes in value.

Eric Lippert has blogged about this - but note that this behaviour may change in future versions of C#.

share|improve this answer
I understand the foreach semantics. But in List<T>.ForEach do you mean the variable v as in the third line is newly created for every iteration? –  Ashley John Aug 20 '11 at 18:48
@Ashley: Yes, because it's the parameter for the lambda expression. Even if you invoked the same delegate twice and the lambda expression modified the value, it wouldn't make any difference - because it's not a captured variable, just a delegate parameter. –  Jon Skeet Aug 20 '11 at 19:08
@FuleSnabel: Any code using that behaviour is already highly likely to be broken. My beef with it is that it allows you to write code which behaves correctly in C# 5 (say) but will compile and behave badly in earlier versions. But maybe that's a price worth paying. –  Jon Skeet Aug 21 '11 at 7:28
@FuleSnabel: We are likely to take the breaking change in the next version. The question is whether the regression will be "major". I think not; as Jon correctly notes, programs that depend on this behaviour are probably already broken. –  Eric Lippert Aug 22 '11 at 15:31
@Eric: Is there a plan for warning anyone compiling code which is intended to work with both C# 4 and C# 5? (I'm thinking primarily of open source projects, where there's no guarantee that all contributors will be using the same version of VS.) I know we've discussed this before - just wondered what the current thinking was. –  Jon Skeet Aug 22 '11 at 18:06

Your Answer


