for和foreach在关闭

时间:2015-10-22 09:51:04

标签: c# for-loop foreach lambda closures

演示代码存在一些问题。

var values = new List<int>() { 100, 110, 120 };  
var funcs = new List<Func<int>>();  

foreach(var v in values)   
    funcs.Add( ()=>v );  

foreach(var f in funcs)   
    Console.WriteLine(f());  
  

大多数人都认为它是100/110/120。实际上是120/120/120。

但结果在vs2015&amp; .net 4.5.1将输出100/110/120,而不是120/120/120

当我按如下方式测试代码时,forforeach之间存在一些差异

var values = new List<int> {100, 110, 120};

var funcs = new List<Func<int>>();
foreach (var v in values)
    funcs.Add(() =>
    {
        Console.WriteLine(v);
        return v;
    } );

foreach (var f in funcs)
    Console.WriteLine(f());

//will throw exception
for (int i=0;i<values.Count;i++)
    funcs.Add(() =>
    {
        Console.WriteLine(values[i]);
        return values[i];
    });

foreach (var f in funcs)
    Console.WriteLine(f());

谁可以在for中的foreachclosures之间向我提供更多详细信息?

1 个答案:

答案 0 :(得分:6)

这是一个不幸的决定的结果,后来C#团队后悔了。 C#5引入的突破性变化最终改变了这种行为。 Quoting Eric Lippert

  

在C#5中,foreach循环变量将在逻辑上位于循环体内,因此闭包每次都会得到一个新的副本。

在C#5之前,闭包都引用了相同的变量绑定。因此,所有调用的输出都是相同的,因为它们都访问了同一个变量的最新值。

然而,从C#5开始,为每次迭代创建 new 变量绑定。这是程序员最有可能采取的行为。