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

Using the iterator variable of foreach loop in a lambda expression - why fails?(在 lambda 表达式中使用 foreach 循环的迭代器变量 - 为什么会失败?)
本文介绍了在 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 循环的迭代器变量 - 为什么会失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

Custom Error Queue Name when using EasyNetQ for RabbitMQ?(使用 EasyNetQ for RabbitMQ 时自定义错误队列名称?)
How to generate password_hash for RabbitMQ Management HTTP API(如何为 RabbitMQ 管理 HTTP API 生成密码哈希)
Rabbitmq Ack or Nack, leaving messages on the queue(Rabbitmq Ack 或 Nack,将消息留在队列中)
Setup RabbitMQ consumer in ASP.NET Core application(在 ASP.NET Core 应用程序中设置 RabbitMQ 消费者)
Specify Publish timeouts in mass transit(指定公共交通中的发布超时)
RabbitMQ asynchronous support(RabbitMQ 异步支持)