问题
I'm creating an array of controls and adding them to the form, and setting their events to a function that receives the index of the clicked button using a lambda expression (b.Click += (sender, e) => myClick(i);
).
But the problem is... Whichever you click on, you receive the index 100, not the real index of the button! What is the problem here?
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());
}
}
}
回答1:
The problem is that you create closure over the loop variable i
. You need to make a local (inside the for
loop) copy of it before passing it to the event handler.
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]);
}
Explanation
You are defining a function like this:
(sender, e) => myClick(i)
This function (which will run at some point in the future, when the button is clicked) includes a reference to i
. The way, this works is that it will use the value of i
at the time when the click occurs, not at the time the function is defined.
By that time, clearly the value of i
will have become 100.
The solution works because it makes the function take a reference to the variable index
instead of i
. index
differs from i
in that i
is one variable whose value changes, while index
is a name we use for 100 different variables (one for each loop iteration), the value of which remains constant.
回答2:
The problem is to do with modified closures. Here is an excellent explanation of the subject by @Jon Skeet.
回答3:
int index = i;
buttons[i].Click += (sender, e) => myClick(index);
Try that.
回答4:
Unfortunately closures (in ur case the variable i) doesn't work the way they should be in C#. Replace
b.Click += (sender, e) => myClick(i);
with
Action<int,Button> act = (index,b) => { b.click += (sender, e) => myClick(index) }
act(i,b);
来源:https://stackoverflow.com/questions/6439477/lambda-expression-not-working-in-setting-the-event-handler-of-some-controls