循环操作列表
我无法理解如何遍历Action
列表。 当我尝试它时,我最终得到的值与前一次迭代相同。
这是代码(简化示例):
string[] strings = { "abc", "def", "ghi" }; var actions = new List(); foreach (string str in strings) actions.Add(new Action(() => { Trace.WriteLine(str); })); foreach (var action in actions) action();
输出:
ghi ghi ghi
为什么在执行操作时总是在strings
选择最后一个元素?
我怎样才能实现所需的输出:
abc def ghi
你的动作是一个闭包,因此它访问str
本身,而不是str
的副本:
foreach (string str in strings) { var copy = str; // this will do the job actions.Add(new Action(() => { Trace.WriteLine(copy); })); }
这是一个相当复杂的情况。 简短的回答是在将局部变量赋值给闭包之前创建它的副本:
string copy = str; actions.Add(new Action(() => { Trace.WriteLine(copy); }));
有关更多信息, 请查看有关闭包的文章 。
此行为由闭包调节。
lambda中存在的变量是引用而不是值副本。 这意味着指向str
假定的最新值,在您的情况下为“ghi”。 这就是为什么每次通话它都会进入相同的内存位置并自然地恢复相同的值。
如果您编写代码(如提供的答案),则强制C#
编译器每次都重新生成一个新值,因此新地址将传递给labmda,因此每个lambda都将拥有它自己的变量。
顺便说一句,如果我没有错, C#
团队承诺在C# 5.0
修复这种非自然行为。 所以最好在这个主题上查看他们的博客,以便将来更新。