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