The other day I published a blog post showing an example of how extension methods can be used to hide infrastructure code. Today's post runs along the same lines, but instead aims to encapsulate a little code snippet that is repeated whenever you deal with events. Let's take it from the start to the end (but I'll still keep it rather brief).

An event declaration will typically look something like this:

public event EventHandler<EventArgs> SomeEvent;

Then, in the type that raises the event, you will have a method called On[EventName], that carries out the task of actually raising the event:

protected void OnSomeEvent(EventArgs e)
{
    EventHandler<EventArgs> temp = SomeEvent;
    if (temp != null)
    {
        temp(this, e);
    }
}

An event is null if it has no event handler attached to it. What you see here is the recommended pattern for raising events. The step of assigning the event to the temp variable is taken in order to avoid a race condition where the event may have an event listener when performing the null check, but then the event handler is detached from the event after the null check (by another thread), but before the event is invoked. That would lead to a NullReferenceException, and we don't want that here.

Events inherit from MulticastDelegate, which is an immutable type, so by simply assigning the event to a variable, we have shielded our code from any subsequent changes to the invocation list of the event; since any such modification will cause SomeEvent to refer to a completely new MulticastDelegate instance; our local copy is still referring to the old one. (There is a quirk here that I will bring up in the end)

Bottom line is; the code pattern above is a candidate for being repeated for each and every event in your code. And we don't like repetition, do we? This can easily be taken care of by a simple extension method:

public static class EventHandlerExtensions
{
    public static void SafeInvoke<T>(this EventHandler<T> evt, object sender, T e) where T : EventArgs
    {
        if (evt != null)
        {
            evt(sender, e);
        }
    }
}

This means that the OnSomeEvent method above can be reduced to this one-liner:

protected void OnSomeEvent(EventArgs e)
{
    SomeEvent.SafeInvoke(this, e);
}

Two notes

You may wonder thy I did not have to assign the event to a temporary variable in the extension method as I needed to do in the first version of OnSomeEvent. Give it a thought and see if you can figure it out. Here is the answer: when passing the event as an argument to the extension method, the argument becomes our local variable that will continue to refer to the old instance of the event in case of any modifications.

And lastly, the quirk. While the presented code pattern does protect the code from throwing a NullReferenceException, we may experience another scenario, which is sort of the opposite. Say we have an event handler attached, the null check is performed, and then the event handler is detached before the event is raised. The method raising the event will still have the now detached event handler in its invocation list for the event, so it will indeed get invoked. This means that there is a possibility (small, but real) that an event handler is invoked after it has been detached.


I am working for a great consultancy company called Diversify, located in Sweden. We are hiring skilled .NET developers. If you are interested, don't hesitate to get in touch with me.

Comments

March 12. 2010 16:54

trackback

Extension method for safe event invokations

You've been kicked (a good thing) - Trackback from DotNetKicks.com

DotNetKicks.com