为什么我在调用 Func时得到错误的结果?
我在 C# 中有以下代码片段:
var actions = new List<Func<int>>();
IEnumerable<int> values = new List<int> { 1, 2, 3 };
foreach (int value in values)
{
actions.Add(() => value * value);
}
foreach (var action in actions)
{
Console.WriteLine(action()); ;
}
Console.ReadLine();
它运行良好,但我没有得到我期望的结果。
实际结果
9,9,9
预期结果
1,4,9
为什么我没有得到预期的结果?
I have the following code snippet in C#:
var actions = new List<Func<int>>();
IEnumerable<int> values = new List<int> { 1, 2, 3 };
foreach (int value in values)
{
actions.Add(() => value * value);
}
foreach (var action in actions)
{
Console.WriteLine(action()); ;
}
Console.ReadLine();
It's running fine, but I am not getting the result I expect.
Actual result
9,9,9
Expected result
1,4,9
Why am I not getting the result I expect?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要捕获循环内的变量。现在,您的延迟执行操作正在使用第一个
foreach
循环中value
的最后一个值。请注意
var v = value;
行。You need to capture the variable inside the loop. Right now your delayed execution actions are using the last value of
value
from the firstforeach
loop.Note the
var v = value;
line.您正在捕获 lambda 表达式中的循环变量,这意味着当最终调用委托时,它会看到循环变量的最终值。
简单修复:
通过这种方式,您可以在循环的每次迭代中获得一个新的
copy
变量,因此每个委托表达式将捕获不同的变量,并且它们不受循环变量(value
)随着时间的推移而变化。Eric Lippert 在 “关闭被认为有害的循环变量”(和 第二部分< /a>)。
基本上,这是 C# 中的一个“陷阱”,几乎每个人迟早都会陷入其中。
You're capturing the loop variable within your lambda expression, which means when the delegate is finally invoked, it's seeing the final value of the loop variable.
Simple fix:
This way you get a new
copy
variable in each iteration of the loop, so each delegate expression will capture a different variable, and they're not affected by the loop variable (value
) changing over time.Eric Lippert explains this well in "Closing over the loop variable considered harmful" (and part two).
Basically this is a "gotcha" in C# which nearly everyone falls for sooner or later.