basti
basti

Reputation: 2689

Autounsubscribe events

I have a static class which publishes a few events. So I have many different small classes that have different lifetimes that subscribe to this event.

I found out now that this leads to memory "leaks" because of the subscribing classes staying alive when they subscribed a longer-living event. I know that this is happening by using a memoryprofiler and I read about this problem.

I am not able to manually unsubscribe, as I might have hundreds of "clients" in a list. This list will just get cleared. So I can't (and don't want to) unsubscribe by hand.

I read that the "weak event pattern" might help here. Could someone please lead me to an "easy" way to implement this? All I found until now is either too simple to use in practice or too complicated to understand it in the beginning.

Or is there any "best practice" for this case?

Thanks in advance!

UPDATE: Based on jbl's answer I found this (http://blogs.msdn.com/b/greg_schechter/archive/2004/05/27/143605.aspx) as a possible solution. Any comments here? It's rather old (2004), so there might be better solutions out there?

Upvotes: 1

Views: 281

Answers (2)

jbl
jbl

Reputation: 15413

Never implemented something like that, but I would try (with a static class or a singleton, your choice) :

  • having the static class maintain a static collection of WeakReference to the client event handlers
  • the clients do not subscribe directly to the event. The static class exposes subscribe and unsubscribe methods which add/remove the handlers from the weak references collection
  • the static class is the only one subscribing directly to the event
  • upon event triggering, the static class enumerates the weak references collection and runs the handlers for the references which are still alive (removing the null ones)

Hope this will help

Upvotes: 1

Ignacio Soler Garcia
Ignacio Soler Garcia

Reputation: 21855

Best practice: always implement the Dispose pattern when a class subscribes to an event generated by an object not constructed by this class.

Then in the Dispose method remove the handler.

public NotificationServiceAccessor(ObjectWithEvent objectWithEvent)
{
    _notificationService = new NotificationService();
    _notificationService.StatusChanged += NotificationService_StatusChanged; // Local object, no Dipose

    _objectWithEvent = objectWithEvent;
    _objectWithEvent.AnEvent += AnEventHandler(); // Event that has to be disposed.
}

    #region IDisposable Members

    protected bool Disposed { get; private set; }

    private void Dispose(bool disposing)
    {
        if (!this.Disposed)
        {
            this.InternalDispose(disposing);
        }

        this.Disposed = true;
    }

    protected virtual void InternalDispose(bool disposing)
    {
        if (disposing)
        {
                        // Dispose here the event handlers
                        _objectWithEvent.AnEvent -= AnEventHandler()
        }

        // Dispose here only unmanaged objects 
        // Don’t use managed objects here because maybe 
        // they have been finalized already
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~NotificationServiceAccessor()
    {
        this.Dispose(false);
    }

    #endregion

Upvotes: 1

Related Questions