This week Im teaching the course I co-wrote with Kevin Jones "Code Smarter with Design Patterns in .NET", as part of the course we introduce the observer pattern and whilst the first part of the deck deals with the basic principles we soon move on to the prefered way of doing it in .NET using delegates/events.
When using events in a multi threaded environment care needs to be taken as whilst register/unregister of the events is thread safe, care needs to be taken when raising the event.
Typically we see code like this
Public class Subject
{
public event EventHandler<EventArgs> Alert;
// ...
protected virtual void OnAlert(EventArgs args)
{
If ( Alert != null )
{
Alert( this , args )
}
}
}
Here a check is being made to make sure the delegate chain has at least one instance, however whilst this works in a single threaded environment in a multithreaded environment there is a race condition between the if and the firing of the event.
To get around this problem, one way is to take a local copy of the delegate reference, and compare that. Since register/unregister events build new lists thus making the register/unregister thread safe. However there is a simpler approach and that is to use the null pattern
public event EventHandler<EventArgs> Alert = delegate { };
This will simple create a delegate instance at the head of the delegate chain which is never removed. Thus its then safe to simply do
Alert( this , args )
Without checking for null, since that can't happen. Ok there is an overhead, but it certainly makes the logic simpler and less prone to occasional hard to find race conditions. Remembering to do this could be a pain so I wrote a simple snippet to do it...So now I simply type safeevent TAB TAB and I always get an event with a null handler...another great use of anonymous methods...
No comments:
Post a Comment