迭代List并在匿名函数中使用对象

本文关键字:对象 函数 List 迭代 | 更新日期: 2023-09-27 17:48:59

我有一个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函数都传递给集合中的最后一项?

迭代List并在匿名函数中使用对象

foreach循环正在改变在lambda中使用的s。lambda在执行时使用s的当前值,而不是声明它(用技术术语来说:"闭包关闭变量,而不是值")。你必须创建一个局部变量:

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

因此,在声明点有对s实例的引用,而不是在执行点。

Eric Lippert有两篇很棒的文章:第1部分,第2部分。