How to defer execution of an Event on each item in a collection until iteration of collection is complete using delegates and/or events?

StackOverflow https://stackoverflow.com/questions/2619005

Question

Of Note: This is more of a curiosity question than anything else.

Given a List<Window> where each window has an event attached to the Close Event which removes the window from the collection, how could you use delegates / events to defer the execution of the Close Event until the collection has been iterated?

For example:

public class Foo
{

    private List<Window> OpenedWindows { get; set; }

    public Foo()
    {
        OpenedWindows = new List<Window>();
    }

    public void AddWindow( Window win )
    {
        win.Closed += OnWindowClosed;
        OpenedWindows.Add( win );
    }

    void OnWindowClosed( object sender, EventArgs e )
    {
        var win = sender as Window;

        if( win != null )
        {
            OpenedWindows.Remove( win );
        }
    }

    void CloseAllWindows()
    {
        // obviously will not work because we can't 
        // remove items as we iterate the collection 
        // (the close event removes the window from the collection)
        OpenedWindows.ForEach( x => x.Close() );

        // works fine, but would like to know how to do
        // this with delegates / events.
        while( OpenedWindows.Any() )
        {
            OpenedWindows[0].Close();
        } 
    }

}

Specifically, within the CloseAllWindows() method, how could you iterate the collection to call the close event, but defer the event being raised until the collection has been completely iterated?

Was it helpful?

Solution

Presumably you're trying to avoid the "Collection was modified" exception in the first case.

Really the only way to "defer" this is to make a copy of the collection, which involves iterating the original collection fully and adding the items to a new collection:

var openedWindowsCopy = new List<Window>(OpenedWindows);
foreach (var window in openedWindowsCopy)
    window.Close();

Also, your second method is valid, although typically when you need to clean up instances in an indexed collection such as a List<T>, you do it simply by counting down:

for (int i = OpenedWindows.Count - 1; i >= 0; i--)
    OpenedWindows[i].Close();

Personally, I see no reason to complicate the issue with more delegates.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top