Captured Variables in Lambda Expressions: Demystifying the "foreach Loop Variable" Mystery
Consider the perplexing code below, which aims to create a list of methods that greet various data types:
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; } }
However, when you run this code, you encounter an unexpected result: it prints "Hi Int32" thrice, instead of the intended "Hi String", "Hi Single", "Hi Int32". What's going on here?
The Subtlety of Closures and Captured Variables
The key to understanding this behavior lies in the concept of closures and captured variables. When a lambda expression is created, it captures the variables from its surrounding scope. In this case, the lambda expression captures the type variable from the foreach loop.
Captured Loop Variables: A Pitfall
Crucially, the captured variable is not the value of type, but the variable itself. As the loop progresses, the type variable changes, while the lambda expressions still refer to the same captured variable.
Correcting the Issue
To achieve the intended behavior, it is necessary to create a new variable within the loop to capture the intended value. Here's how to modify the code:
foreach (var type in types) { var newType = type; var sayHello = new PrintHelloType(greeting => SayGreetingToType(newType, greeting)); helloMethods.Add(sayHello); }
By capturing newType instead of type, the lambda expressions now have a constant reference to the intended value, and the expected output is obtained.
Conclusion
Understanding the intricacies of closures and captured variables is essential when working with lambda expressions. By being mindful of these mechanics, you can avoid unexpected behaviors and ensure your code operates as intended.
The above is the detailed content of Why do all lambda expressions in a foreach loop capture the same variable instead of their individual values?. For more information, please follow other related articles on the PHP Chinese website!