考虑这段代码。
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
}
我知道由于lambda捕获的闭包变量,第二个foreach打印768次3次。为什么在第一种情况下不会发生?foreach
关键字与方法Foreach
有何不同?是否因为当我values.ForEach
答案 0 :(得分:9)
foreach
仅介绍一个变量。虽然lambda参数变量在每次调用时都是“新鲜的”。
与:比较:
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
}
即,
foreach (T v in ...) { }
可以被认为是:
T v;
foreach(v in ...) {}
快乐的编码。
答案 1 :(得分:6)
不同之处在于,在foreach
循环中,您获得了一个单变量v1
。该变量采用values
中的每个值 - 但您只是在最后使用 ...这意味着我们每次只能看到最终值。
在List<T>.ForEach
版本中,每次迭代都会引入一个新变量(参数f
) - 因此每个lambda表达式都捕获一个单独的变量,该变量的值永远不会改变。
Eric Lippert已blogged about this - 但请注意,此行为可能在C#的未来版本中发生变化。