2011-04-04 67 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