Home >

Some tips on events

19. November 2008
public class PluginService:IPluginService
{
    public event EventHandler<EventArgs> PluginStarted;
    public event EventHandler<EventArgs> PluginStarting;
    public void StartPlugin(int id)
    {
        PluginStarting(this, EventArgs.Empty);
        //Do some work
        PluginStarted(this, EventArgs.Empty);
    }
}

There is something obviously wrong with this code.

First of all, it is not doing the null check on the event. One should not assume that event will always have handlers.

There are 2 solutions to that issue:

  1. Dummy operation  
    public class PluginService:IPluginService
    {
        public event EventHandler<EventArgs> PluginStarted = delegate { };
        public event EventHandler<EventArgs> PluginStarting = delegate { };
        public void StartPlugin(int id)
        {
            PluginStarting(this, EventArgs.Empty);
            //Do some work
            PluginStarted(this, EventArgs.Empty);
        }
    }


    or some people prefer null object pattern but it is restricted to some specific delegate type.

    public class PluginService:IPluginService
    {
        public event EventHandler<EventArgs> PluginStarted = NullSubscriber.For<EventArgs>();
        public event EventHandler<EventArgs> PluginStarting = NullSubscriber.For<EventArgs>();
        public void StartPlugin(int id)
        {
            PluginStarting(this, EventArgs.Empty);
            //Do some work
            PluginStarted(this, EventArgs.Empty);
        }
    }

     

  2. Null Check
    First try would be to do the null check with a simple if:

    public class PluginService:IPluginService
    {
        public event EventHandler<EventArgs> PluginStarted;
        public event EventHandler<EventArgs> PluginStarting;
        public void StartPlugin(int id)
        {
            if (PluginStarting != null)
                PluginStarting(this, EventArgs.Empty);
            //Do some work
            if (PluginStarted!=null)
                PluginStarted(this, EventArgs.Empty);
        }
    }

    This wouldn’t work, since during the execution after the if is evaluated, the event handler may unsubscribe from the event, which will result in a null reference exception in the runtime(which is hard to catch in development)

    Another and the correct one try is:
    public class PluginService:IPluginService
    {
        public event EventHandler<EventArgs> PluginStarted;
        public event EventHandler<EventArgs> PluginStarting;
        public void StartPlugin(int id)
        {
            var handler = PluginStarting;
            if (handler != null)
                handler(this, EventArgs.Empty);
            //Do some work
            handler = PluginStarted;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }
    }


    The key point here is not the null check, but how we do the null check. Since the events are immutable, we are now free to assign it. It won’t cause an issue when one of the subscribers unsubscribe.
    (thanks to
    Ayende for reminding us the Race condition)

I think this is enough for the first post

kick it on DotNetKicks.com

, ,

Comments

Comments are closed