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
版本中,每次迭代都会引入一个新变量(参数f
) – 因此每个lambda表达式都捕获一个单独的变量,该变量的值不会改变。
Eric Lippert在博客中发表过这篇文章 – 但请注意,这种行为可能会在未来的C#版本中发生变化。
- 当取消选中复选框时,asp:复选框的OnCheckedChanged事件处理程序不会触发
- 无法使用c#导航到Windows Metro App上的页面
- C#Alter Table并以编程方式添加一列ASP.Net和SQL Server
- 枚举并将属性从一个对象复制到另一个相同类型的对象
- 是否有validation用户输入的最佳实践方法?
- c#替代socket.io for node.js
- 通过ASP.NET身份2中的UserManager.Update()更新用户
- DateTimeStyles.RoundtripKind枚举是什么意思?
- 修改DAL,System.ArgumentException时出错,“已存在具有相同密钥的条目”