考虑以下初始化委托列表的代码,每个委托都调用具有特定类型和问候语的 SayGreetingToType 方法:
<code class="csharp">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) { // Initialize the lambda expression with the captured variable 'type' var sayHello = new PrintHelloType(greeting => SayGreetingToType(type, greeting)); helloMethods.Add(sayHello); } // Call the delegates with the greeting "Hi" foreach (var helloMethod in helloMethods) { Console.WriteLine(helloMethod("Hi")); } } public string SayGreetingToType(Type type, string greetingText) { return greetingText + " " + type.Name; } }</code>
执行此代码后,您会期望看到:
Hi String Hi Single Hi Int32
但是,由于闭包行为,类型数组中的最后一个类型 Int32 被所有 lambda 捕获表达式。因此,所有委托都以相同的类型调用 SayGreetingToType,导致意外输出:
Hi Int32 Hi Int32 Hi Int32
解决方案
要解决此问题,我们需要捕获 lambda 表达式中循环变量的值而不是变量本身:
<code class="csharp">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) { // Capture a copy of the current 'type' value using a new variable var newType = type; // Initialize the lambda expression with the new variable 'newType' var sayHello = new PrintHelloType(greeting => SayGreetingToType(newType, greeting)); helloMethods.Add(sayHello); } // Call the delegates with the greeting "Hi" foreach (var helloMethod in helloMethods) { Console.WriteLine(helloMethod("Hi")); } } public string SayGreetingToType(Type type, string greetingText) { return greetingText + " " + type.Name; } }</code>
此修改可确保每个 lambda 表达式都有自己的类型副本,从而允许它使用正确的值调用 SayGreetingToType输入参数。
以上是为什么 Foreach 循环内的 Lambda 表达式会捕获循环变量的最后一个值?的详细内容。更多信息请关注PHP中文网其他相关文章!