Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Lambda表达式在设置某些控件的事件处理程序时不起作用_C#_Winforms_Event Handling_Lambda - Fatal编程技术网

C# Lambda表达式在设置某些控件的事件处理程序时不起作用

C# Lambda表达式在设置某些控件的事件处理程序时不起作用,c#,winforms,event-handling,lambda,C#,Winforms,Event Handling,Lambda,我正在创建一个控件数组并将它们添加到表单中,并将它们的事件设置为一个函数,该函数使用lambda表达式接收单击按钮的索引(b.Click+=(sender,e)=>myClick(I);) 但问题是。。。无论单击哪个按钮,都会收到索引100,而不是按钮的实际索引!这里有什么问题 namespace testArrayOfControls { public partial class Form1 : Form { Button[] buttons;

我正在创建一个控件数组并将它们添加到表单中,并将它们的事件设置为一个函数,该函数使用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());
        }

    }
}
namespace testArrayOfControls
{
公共部分类Form1:Form
{
按钮[]按钮;
公共表格1()
{
初始化组件();
按钮=新按钮[100];
对于(int i=0;i<100;i++)
{
按钮[i]=新按钮();
按钮[i]。设置边界(i%10*50,i/10*50,50,50);
按钮[i]。单击+=(发件人,e)=>myClick(i);
this.Controls.Add(按钮[i]);
}
}
私有void myClick(int i)
{
Show(i.ToString());
}
}
}

问题是在循环变量
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]);
}
此功能(将来单击按钮时将在某个点运行)包括对
i
的引用。其工作方式是,它将在单击发生时使用
i
的值,而不是在定义函数时

到那时,
i
的值显然将变为100

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

试试看

问题与修改的闭包有关。是@Jon Skeet对这个主题的一个很好的解释。

不幸的是,闭包(在我们的例子中,变量i)的工作方式与C#中的工作方式不同。 替换

Action-act=(索引,b)=>{b.click+=(发送者,e)=>myClick(索引)}
法案(i,b);
在这里阅读我的答案:
(sender, e) => myClick(i)
int index = i; 
buttons[i].Click += (sender, e) => myClick(index);
b.Click += (sender, e) => myClick(i);
Action<int,Button> act = (index,b) => { b.click += (sender, e) => myClick(index) }
act(i,b);