考慮以下初始化委託列表的程式碼,每個委託都呼叫具有特定類型和問候語的SayGreetingToType 方法:
<code class="csharp">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) { // Initialize the lambda expression with the captured variable 'type' var sayHello = new PrintHelloType(greeting => SayGreetingToType(type, greeting)); helloMethods.Add(sayHello); } // Call the delegates with the greeting "Hi" foreach (var helloMethod in helloMethods) { Console.WriteLine(helloMethod("Hi")); } } public string SayGreetingToType(Type type, string greetingText) { return greetingText + " " + type.Name; } }</code>
執行此程式碼後,您會期望看到:
Hi String Hi Single Hi Int32
但是,由於閉包行為,類型數組中的最後一個類型Int32 被所有lambda 捕獲表達式。因此,所有委託都以相同的類型呼叫SayGreetingToType,導致意外輸出:
Hi Int32 Hi Int32 Hi Int32
解決方案
要解決此問題,我們需要捕獲lambda 表達式中循環變數的值而不是變數本身:
<code class="csharp">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) { // Capture a copy of the current 'type' value using a new variable var newType = type; // Initialize the lambda expression with the new variable 'newType' var sayHello = new PrintHelloType(greeting => SayGreetingToType(newType, greeting)); helloMethods.Add(sayHello); } // Call the delegates with the greeting "Hi" foreach (var helloMethod in helloMethods) { Console.WriteLine(helloMethod("Hi")); } } public string SayGreetingToType(Type type, string greetingText) { return greetingText + " " + type.Name; } }</code>
此修改可確保每個lambda 表達式都有自己的類型副本,從而允許它使用正確的值呼叫SayGreetingToType輸入參數。
以上是為什麼 Foreach 迴圈內的 Lambda 表達式會捕捉循環變數的最後一個值?的詳細內容。更多資訊請關注PHP中文網其他相關文章!