演示代码存在一些问题。
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 。
当我按如下方式测试代码时,for
和foreach
之间存在一些差异
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
中的foreach
和closures
之间向我提供更多详细信息?
答案 0 :(得分:6)
这是一个不幸的决定的结果,后来C#团队后悔了。 C#5引入的突破性变化最终改变了这种行为。 Quoting Eric Lippert:
在C#5中,foreach循环变量将在逻辑上位于循环体内,因此闭包每次都会得到一个新的副本。
在C#5之前,闭包都引用了相同的变量绑定。因此,所有调用的输出都是相同的,因为它们都访问了同一个变量的最新值。
然而,从C#5开始,为每次迭代创建 new 变量绑定。这是程序员最有可能采取的行为。