Lambda表达式无法设置某些控件的事件处理程序

Hos*_*ein 3 c# lambda event-handling winforms

我正在创建一个控件数组并将它们添加到表单中,并将它们的事件设置为一个函数,该函数使用lambda表达式(b.Click += (sender, e) => myClick(i);)接收所单击按钮的索引.

但问题是......无论你点击什么,你都会收到索引100,而不是按钮的真实索引!这里有什么问题?

namespace testArrayOfControls
{

    public partial class Form1 : Form
    {
        Button[] buttons;

        public Form1()
        {
            InitializeComponent();
            buttons = new Button[100];
            for (int i = 0; i < 100; i++)
            {
                buttons[i] = new Button();
                buttons[i].SetBounds(i % 10 * 50, i / 10 * 50, 50, 50);
                buttons[i].Click += (sender, e) => myClick(i);
                this.Controls.Add(buttons[i]);
            }
        }

        private void myClick(int i)
        {
            MessageBox.Show(i.ToString());
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*Jon 5

问题是你在循环变量上创建了闭包i.for在将其传递给事件处理程序之前,您需要创建一个本地(在循环内)的副本.

for (int i = 0; i < 100; i++)
{
    var index = i; // YOU NEED TO DO THIS
    buttons[i] = new Button();
    buttons[i].SetBounds(i % 10 * 50, i / 10 * 50, 50, 50);
    buttons[i].Click += (sender, e) => myClick(index); // THIS SOLVES THE PROBLEM
    this.Controls.Add(buttons[i]);
}
Run Code Online (Sandbox Code Playgroud)

说明

你正在定义一个这样的函数:

(sender, e) => myClick(i)
Run Code Online (Sandbox Code Playgroud)

此功能(将在以后的某个时刻运行,当单击按钮时)包含对其的引用i.这样做的方法是,它将使用i 点击发生时的值,而不是定义函数时的值.

到那时,显然,i意志的价值已经变为100.

该解决方案有效,因为它使该函数引用变量index而不是i.index不同之处在于i,它i是一个值变化的变量,index而是我们用于100个不同变量的名称(每个循环迭代一个),其值保持不变.