开发者

How do closures differ between foreach and list.ForEach()?

Consider this code.

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

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

        values.ForEach(v=>funcs.Add(()=>v));

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

        funcs.Clear();

        foreach (var v1 in values)
        {
            funcs.Add(()=>v1);
        }

        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 metho开发者_开发百科d Foreach? Is it beacuse the expression is evaluated when i do values.ForEach


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.


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#.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜