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中文网其他相关文章!