在 lambda 表达式中使用 foreach 循环的迭代器变量 - 为什么会失败?

时间:2023-03-26
本文介绍了在 lambda 表达式中使用 foreach 循环的迭代器变量 - 为什么会失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

考虑以下代码:

公共类 MyClass{公共委托字符串 PrintHelloType(字符串问候语);公共无效执行(){Type[] types = new Type[] { typeof(string), typeof(float), typeof(int)};列表<PrintHelloType>helloMethods = 新列表<PrintHelloType>();foreach(类型中的 var 类型){var sayHello =new PrintHelloType(greeting => SayGreetingToType(type, greeting));helloMethods.Add(sayHello);}foreach(helloMethods 中的 var helloMethod){Console.WriteLine(helloMethod("Hi"));}}public string SayGreetingToType(Type type, string greetingText){返回 greetingText + " " + type.Name;}...}

调用myClass.Execute()后,代码打印出以下意外响应:

<上一页>嗨 Int32嗨 Int32嗨 Int32

显然,我希望 "Hi String""Hi Single""Hi Int32",但显然不是案件.为什么在所有 3 种方法中都使用迭代数组的最后一个元素而不是适当的方法?

您将如何重写代码以实现预期目标?

解决方案

欢迎来到闭包和捕获变量的世界:)

Eric Lippert 对此行为有深入的解释:

  • 结束在被认为有害的循环变量上
  • 结束在循环变量上,第二部分

基本上,捕获的是循环变量,而不是值.要获得您认为应该获得的东西,请执行以下操作:

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

Consider the following code:

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;
    }

...

}

After calling myClass.Execute(), the code prints the following unexpected response:

Hi Int32
Hi Int32
Hi Int32  

Obviously, I would expect "Hi String", "Hi Single", "Hi Int32", but apparently it is not the case. Why the last element of the iterated array is being used in all the 3 methods instead of the appropriate one?

How would you rewrite the code to achieve the desired goal?

解决方案

Welcome to the world of closures and captured variables :)

Eric Lippert has an in-depth explanation of this behaviour:

  • Closing over the loop variable considered harmful
  • Closing over the loop variable, part two

basically, it's the loop variable that is captured, not it's value. To get what you think you should get, do this:

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

这篇关于在 lambda 表达式中使用 foreach 循环的迭代器变量 - 为什么会失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:使用 PhysicalAddress 作为键时字典中的重复键 下一篇:C# 或滑动窗口枚举器中的成对迭代

相关文章