一尘不染

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

c#

考虑以下代码:

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

...

}

调用之后myClass.Execute(),代码将输出以下意外响应:

嗨Int32
嗨Int32
嗨Int32

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

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


阅读 328

收藏
2020-05-19

共1个答案

一尘不染

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

埃里克·利珀特(Eric Lippert)对这种行为有深入的解释:

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

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