views:

151

answers:

1

Hi. I'm trying to iterate through all components and for those who implements ISupportsOpen allow to open a project. The problem is when the anonymous method is called, then the component variable is always the same element (as coming from the outer scope from IEnumerable)

foreach (ISupportsOpen component in something.Site.Container.Components.OfType<ISupportsOpen>())
{
    MyClass m = new MyClass();  
    m.Called += new EventHandler(delegate(object sender, EventArgs e)
    {                           
        if (component.CanOpenProject(..)) component.OpenProject(..);
    });

    itemsList.Add(m);
}

How should it be solved, please?

+4  A: 

Just don't close over the loop variable - copy it:

foreach (ISupportsOpen component in 
         something.Site.Container.Components.OfType<ISupportsOpen>())
{
    ISupportsOpen copy = component;
    MyClass m = new MyClass();  
    m.Called += new EventHandler(delegate(object sender, EventArgs e)
    {                           
        if (copy.CanOpenProject(..)) copy.OpenProject(..);
    });

    itemsList.Add(m);
}

This way you get a new "instance" of the copy variable for each iteration of the loop - so each delegate will capture that different instance. Before, every delegate was capturing the same variable.

(This is in some ways a duplicate question, but it's the kind of problem which is relatively hard to search for, so I'm happy to answer it many times.)

Jon Skeet
I'm just curious, why doesn't the run-time hold that instance in memory when he knows that the instance is being used? Why was the delegate before capturing the same variable ?
PaN1C_Showt1Me
@PaN1C_Showt1Me: The language specification defines `foreach` in terms of a single variable; that variable is captured, so it's all working according to the spec. (It's a language thing rather than a run-time thing.) See Eric's blog post (linked) for further details. I'm sure if the language designers had a time machine, they'd change the behaviour of foreach - but it's too late now.
Jon Skeet