Проблема с анонимным делегатом внутри foreach - PullRequest
4 голосов
/ 03 апреля 2010
    public Form1()
    {
        InitializeComponent();
        Collection<Test> tests = new Collection<Test>();
        tests.Add(new Test("test1"));
        tests.Add(new Test("test2"));
        foreach (Test test in tests)
        {
            Button button = new Button();
            button.Text = test.name;
            button.Click+=new EventHandler((object obj, EventArgs arg)=>{
                this.CreateTest(test);
            });
            this.flowLayoutPanel1.Controls.Add(button);
        }
    }
    public void CreateTest(Test test)
    {
        MessageBox.Show(test.name);
    }
}

когда я нажимаю кнопку с текстом «test1», в окне сообщения будет «test2», но я ожидаю «test1».Итак, кто-нибудь, пожалуйста, скажите мне, почему или что не так с моим кодом.

1 Ответ

14 голосов
/ 03 апреля 2010

Yup - вы закрываете переменную цикла. test в лямбда-выражении ссылается на одну и ту же переменную во всех ваших делегатах, что означает, что она будет иметь окончательное значение в конце цикла. Возьмите копию стоимости и используйте ее. Вы также используете довольно длинную форму лямбда-выражения. Вот исправленный и сокращенный код:

foreach (Test test in tests)
{
    // Take a copy of the "test" variable so that each iteration
    // creates a delegate capturing a different variable (and hence a
    // different value)
    Test copy = test;
    Button button = new Button();
    button.Text = test.name;
    button.Click += (obj, arg) => CreateTest(copy);
    this.flowLayoutPanel1.Controls.Add(button);
}

См. сообщение Эрика Липперта в блоге на эту тему для получения дополнительной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...