foreach和list.ForEach()之间的闭包有何不同?

考虑这段代码。

var values = new List {123, 432, 768}; var funcs = new List<Func>(); 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 } 

我知道第二个foreach打印768次3次因为lambda捕获的闭包变量。 为什么在第一种情况下不会发生? foreach关键字与Foreach方法有何不同? 是不是因为当我做值时,表达式被评估values.ForEach

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 ...) {} 

快乐的编码。

不同之处在于,在foreach循环中,您获得了一个捕获的变量v1 。 该变量采用值中的每个values – 但您最后只使用它…这意味着我们每次只能看到最终值。

List.ForEach版本中,每次迭代都会引入一个新变量(参数f ) – 因此每个lambda表达式都捕获一个单独的变量,该变量的值不会改变。

Eric Lippert在博客中发表过这篇文章 – 但请注意,这种行为可能会在未来的C#版本中发生变化。