首页  >  文章  >  后端开发  >  为什么 foreach 循环中的所有 lambda 表达式捕获相同的变量而不是它们各自的值?

为什么 foreach 循环中的所有 lambda 表达式捕获相同的变量而不是它们各自的值?

Patricia Arquette
Patricia Arquette原创
2024-10-28 22:16:30445浏览

Why do all lambda expressions in a foreach loop capture the same variable instead of their individual values?

Lambda 表达式中捕获的变量:揭开“foreach 循环变量”之谜

考虑下面令人困惑的代码,其目的是创建一个列表迎接各种数据类型的方法:

public class MyClass
{
    public delegate string PrintHelloType(string greeting);

    public void Execute()
    {
        Type[] types = new Type[]{typeof(string), typeof(float), typeof(int)};
        List<PrintHelloType> helloMethods = new List<PrintHelloType>();

        foreach (var type in types) {
            var sayHello = new PrintHelloType(greeting => SayGreetingToType(type, greeting));
            helloMethods.Add(sayHello);
        }

        foreach (var helloMethod in helloMethods) {
            Console.WriteLine(helloMethod("Hi"));
        }
    }

    public string SayGreetingToType(Type type, string greetingText) {
        return greetingText + " " + type.Name;
    }
}

但是,当您运行此代码时,您会遇到意想不到的结果:它打印了三次“Hi Int32”,而不是预期的“Hi String”、“Hi单”、“嗨 Int32”。这是怎么回事?

闭包和捕获变量的微妙之处

理解这种行为的关键在于闭包和捕获变量的概念。创建 lambda 表达式时,它会从其周围范围捕获变量。在这种情况下,lambda 表达式从 foreach 循环中捕获类型变量。

捕获的循环变量:一个陷阱

至关重要的是,捕获的变量不是类型,但变量本身。随着循环的进行,类型变量发生变化,而 lambda 表达式仍然引用相同的捕获变量。

纠正问题

为了实现预期的行为,它有必要在循环中创建一个新变量来捕获预期值。以下是修改代码的方法:

foreach (var type in types) {
   var newType = type;
   var sayHello = new PrintHelloType(greeting => SayGreetingToType(newType, greeting));
   helloMethods.Add(sayHello);
}

通过捕获 newType 而不是 type,lambda 表达式现在拥有对预期值的常量引用,并获得预期的输出。

结论

使用 lambda 表达式时,了解闭包和捕获变量的复杂性至关重要。通过留意这些机制,您可以避免意外行为并确保您的代码按预期运行。

以上是为什么 foreach 循环中的所有 lambda 表达式捕获相同的变量而不是它们各自的值?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn