首頁  >  文章  >  後端開發  >  為什麼 foreach 迴圈中的所有 lambda 表達式會捕捉相同的變數而不是它們各自的值?

為什麼 foreach 迴圈中的所有 lambda 表達式會捕捉相同的變數而不是它們各自的值?

Patricia Arquette
Patricia Arquette原創
2024-10-28 22:16:30443瀏覽

Why do all lambda expressions in a foreach loop capture the same variable instead of their individual values?

Lambda 表達式中捕獲的變數:揭開「foreach 循環變數」之謎

考慮下面令人困惑的程式碼,其目的是創建一個清單迎接各種資料類型的方法:

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

但是,當您運行此程式碼時,您會遇到意想不到的結果:它列印了三次“Hi Int32”,而不是預期的「Hi String」、「Hi單」、「嗨Int32」。這是怎麼回事?

閉包和捕獲變數的微妙之處

理解這種行為的關鍵在於閉包和捕獲變數的概念。建立 lambda 表達式時,它會從其周圍範圍捕獲變數。在這種情況下,lambda 表達式會從 foreach 迴圈中擷取類型變數。

捕獲的循環變數:一個陷阱

至關重要的是,捕獲的變數不是類型,而是變數本身。隨著循環的進行,類型變數發生變化,而 lambda 表達式仍然引用相同的捕獲變數。

修正問題

為了實現預期的行為,它有必要在循環中建立一個新變數來捕捉預期值。以下是修改程式碼的方法:

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

透過擷取 newType 而不是 type,lambda 表達式現在擁有對預期值的常數引用,並獲得預期的輸出。

結論

使用 lambda 表達式時,了解閉包和捕獲變數的複雜性至關重要。留意這些機制,您可以避免意外行為並確保您的程式碼能如預期運作。

以上是為什麼 foreach 迴圈中的所有 lambda 表達式會捕捉相同的變數而不是它們各自的值?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn