循环显示一系列操作
我无法理解如何通过Action
列表循环。 当我尝试它时,我最终得到的值与之前的迭代相同。
以下是代码(简化示例):
string[] strings = { "abc", "def", "ghi" };
var actions = new List<Action>();
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
修复这种非自然行为。 因此,最好查看他们的博客关于这个主题的未来更新。