2011-04-04 59 views
0

我有一個List<string>,我想迭代這個集合,並在按鈕單擊時對每個字符串執行一些操作。我這裏有一個小例子來說明我想要做的事:迭代列表並使用匿名函數內的對象

//items is a System.Collections.Generic.List<string> 
foreach (string s in items) 
{ 
    Button b = new Button() { Content = s }; 
    b.Click += (obj, ev) => 
    { 
     MessageBox.Show(s); 
    } 
    //add b to form, container, etc... 
} 

正如你所期望的按鈕與正確的內容適當地創建,但是當我點擊任何按鈕,裏面的文字MessageBox始終是items中的最後一個字符串。我錯過了什麼?爲什麼按鈕的所有Click函數都被傳遞到集合中的最後一項?

回答

8

foreach循環正在更改s,它在lambda中使用。 lambda在執行時使用s的當前值,而不是聲明它(在techspeak中:「閉合關閉變量,而不是值」)。你必須做一個局部變量:

foreach (string s in items) 
{ 
    string local = s; 
    Button b = new Button() { Content = s }; 
    b.Click += (obj, ev) => 
    { 
     MessageBox.Show(local); 
    } 
    //add b to form, container, etc... 
} 

因此你必須在decleration,不執行點的引用的s實例。

Eric Lippert有兩篇關於它的奇妙文章:part 1,part 2

+1

注意Eric Lippert關於此的博客條目:** [第1部分](http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-被認爲有害.aspx)**和** [第2部分](http://blogs.msdn.com/b/ericlippert/archive/2009/11/16/closing-over-the-loop-variable-part- two.aspx)** – Timwi 2011-04-04 17:17:45

+0

+1輝煌,這是做的伎倆。感謝您的鏈接,精彩文章。 – jmccarthy 2011-04-04 17:32:29