为什么我在调用 Func时得到错误的结果?

发布于 2024-10-26 16:46:22 字数 475 浏览 0 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

纸伞微斜 2024-11-02 16:46:22

您需要捕获循环内的变量。现在,您的延迟执行操作正在使用第一个 foreach 循环中 value 的最后一个值。

var actions = new List<Func<int>>();
        IEnumerable<int> values = new List<int> { 1, 2, 3 };
        foreach (int value in values)
        {
            var v = value;
            actions.Add(() => v * v);
        }
        foreach (var action in actions)
        {
            Console.WriteLine(action()); ;
        }
        Console.ReadLine();

请注意 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 first foreach loop.

var actions = new List<Func<int>>();
        IEnumerable<int> values = new List<int> { 1, 2, 3 };
        foreach (int value in values)
        {
            var v = value;
            actions.Add(() => v * v);
        }
        foreach (var action in actions)
        {
            Console.WriteLine(action()); ;
        }
        Console.ReadLine();

Note the var v = value; line.

尬尬 2024-11-02 16:46:22

您正在捕获 lambda 表达式中的循环变量,这意味着当最终调用委托时,它会看到循环变量的最终值。

简单修复:

foreach (int value in values)
{
    int copy = value;
    actions.Add(() => copy * copy);
}

通过这种方式,您可以在循环的每次迭代中获得一个新的 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:

foreach (int value in values)
{
    int copy = value;
    actions.Add(() => copy * copy);
}

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文