Reputation: 43
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);
}
}
when i click the button witch text is 'test1', the messagebox will show 'test2',but my expect is 'test1'. So ,would anyone please tell me why or what`s wrong with my code.
Upvotes: 4
Views: 514
Reputation: 1504092
Yup - you're closing over the loop variable. The test
within the lambda expression refers to the same variable in all your delegates, which means it will end up with the final value at the end of the loop. Take a copy of the value and use that. You're also using a pretty longwinded form of the lambda expression. Here's the fixed and shortened code:
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);
}
See Eric Lippert's blog post on this topic for more information.
Upvotes: 14