3
votes

I'm facing the following situation (C#/.Net here, but I think it's a general problem):

  • Some of our object types (which are collections) are disposable types (IDisposable in C#, which allows clients to explicitly tell an object 'you are not needed anymore, free all of your resources')
  • These collections fire events ('oh my, look, somebody just added/removed/changed an element').
  • During the running of the collection's client's event handler code, this code decides to dispose the object which has just been sending the event (which, semantically, is a correct action; example: now the collection does not contain any object of interest to me anymore, so I'll get rid of it).

This of course wreaks havoc upon the sending objects.

The current 'solution' is to safeguard (i.e., disallow) disposing while the events are fired:

private bool m_AllowDisposal;

private void MeFiringEvents()
{
    m_AllowDisposal = false;

    // Fire event
    if (m_MyEventHandlers != null)
    {
        m_MyEventHandlers(...);
    }

    m_AllowDisposal = true;
}

public void IDisposable.Dispose()
{
    if (m_AllowDisposal)
    {
        // Dispose resources, set members to null, etc
    }
}

As you can see, this is no real solution, since disposal for the event's sender is effectively inhibited during client's event handling code.

Any other solution I could come up with would be along the lines

  • After each firing of events, check whether disposal (or any other 'bad' modification to the object) has happened in client's event handler code.
  • Get out of the sender's code (which can be deeply nested until it reaches the event firing) in a defensive way.

Interestingly, I did not find any useful information on that topic on the net, although it seems like a general showstopper.

Perhaps you have got an idea.

Thanks for your consideration,

Christian

2
"This of course wreaks havoc upon the sending objects." Why "of course"? Can't you fix this? - Henrik
Well, if immediately after having called your client event handlers all of your member variables have been set to null (by your own dispose method), then this would mean endless if(member != null), which seems rather awkward. - 7enderhead

2 Answers

1
votes

Seems to me that there's a lot of things happening at the same time to keep proper track of.

I would try to separate the "disposal of objects" concern, for example add to-be-disposed items in a queue/disposal manager of some sort which would process (call Dispose on) items in a safer and more well designed/understood and deterministic way. If anything, this should help with debugging the problem.

0
votes

You might consider a different approach if you just need a single listener that should dispose an object, perhaps a simple callback (implementing the Begin/End pattern in .NET).

Disposing of an event's sender isn't ever semantically appropriate: the object that created the collection (or initiated its creation) should be responsible for disposing of it, not an arbitrary observer.