Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with different "execution context" of an anonymous method within a loop

I have a problem with an anonymous method within a loop.

The following code is just to illustrate my problem:

private void Form1_Load(object sender, EventArgs e)
{
    List<string> bassists = new List<string>(){
        "Jaco Pastorius", 
        "Marcus Miller", 
        "Flea", 
        "Vicor Wooten"
    };

    foreach (string item in bassists)
    {
        this.button1.Click += (s, ea) => Output(s, ea, item); 
    }
}

private void Output(object s, EventArgs e, string item)
{
    this.listBox1.Items.Add(item);
}

And when I click into the button, the output is:

Victor Wooten
Victor Wooten
Victor Wooten
Victor Wooten

instead of:

Jaco Pastorius
Marcus Miller
Flea
Vicor Wooten

The main point of my problem is the differents execution context. I know my example is stupid.

like image 500
Florian Avatar asked Dec 10 '10 13:12

Florian


1 Answers

This is the captured variable problem. Fix it by changing

foreach (string item in bassists)
{
    this.button1.Click += (s, ea) => Output(s, ea, item); 
}

to

foreach (string item in bassists)
{
    string currentItem = item;
    this.button1.Click += (s, ea) => Output(s, ea, currentItem); 
}

Here is an explanation of the issue: Closing over loop variable considered harmful. By putting the local variable currentItem in the scope of the loop and closing over that, we now capture that variable instead of the loop variable.

like image 92
jason Avatar answered Sep 20 '22 22:09

jason