16.1 foreach 迴圈中捕獲變數的變化
阿新 • • 發佈:2018-12-18
在 foreach 迴圈內的匿名函式(通常為Lambda表示式)中捕獲迴圈 變數時要格外小心。程式碼清單16-1就展示了這樣一個簡單的示例,它看上去似乎會輸出 x 、 y 、 z 。
1 string[] values = new string[] { "x", "y", "z" }; 2 var actions = new List<Action>(); 3 4 foreach (string value in values) 5 { 6 actions.Add(() => Console.WriteLine(value));7 } 8 9 foreach (Action action in actions) 10 { 11 action(); 12 }
在C# 3和C# 4中,以上程式碼實際上會打印出三個 z 。迴圈變數( value )可由Lambda表示式捕獲,且名義上在迴圈的每次迭代中,只有一個變數“例項”的值發生了變化。全部三個委託都將引用相同的變數,並且在最終執行時,該變數的值為 z 。這並不是編譯器實現上的錯誤,而是語言被指定所產生的行為。
在C# 5中,語言的行為與當初預期的一樣:迴圈的每次迭代都可有效地引入一個單獨變數。 每個委託都引用不同的變數,變數的值就是這次迴圈迭代中產生的值。
有關該特性的內容就講到這裡,它只是修復了會讓很多開發者產生疑惑的語言部分而已。 (Stack Overflow上有超多人詢問這方面的問題。)
但此處要提醒一句:如果編寫的程式碼需用不同版本的C#編譯器進行編譯,則應注意它們產生 的行為是不同的。對於任何版本的C#來說,程式碼清單16-1都不會產生警告,而在C# 5中,行為卻 神不知鬼不覺地發生了改變。要慎之又慎,並且確保有單元測試可以依靠。