Saturday, September 13, 2008

A Rule A Day: UseGenericEventHandlerInstances

Today I’d like to talk about one useful rule, which perhaps I should have mention in my previous post on “Declare event handlers correctly” rule.

The Design rule “Use Generic Event Handler Instances“ UseGenericEventHandlerInstances (CA1003) may be used to identify one of the points I have mentioned in my previous post, namely identify all custom delegate declarations that can be replaced with generic EventHandler<T> delegate.

If you are thinking about defining custom delegate for custom event handlers, the chances are your delegate will return void and will have two parameters - object as first parameter, and derivative of EventArgs as second parameters:

delegate void CustomEventHandler(object sender, CustomEventArgs e);

The only difference from EventHandler delegate definition is the custom second parameter:

delegate void EventHandler(object sender, EventArgs e);

The definition of CustomEventHandler above will violate UseGenericEventHandlerInstances rule; the suggested approach is not to define custom delegate but rather use generic EventHandler<T>. Using generic version of EventHandler allows for using custom event arguments and does not require additional delegate definition. To illustrate, the code that will violate the rule uses custom delegate definition:

public delegate void CustomEventHandler(object sender, CustomEventArgs e);
// violates the rule
 
public class EventProducer
{
    public event CustomEventHandler CustomEvent;
}
 
public class EventConsumer
{
    public void AttachEvent(EventProducer producer)
    {
        producer.CustomEvent += new CustomEventHandler(ProcessEvent);
    }
 
    private void ProcessEvent(object sender, CustomEventArgs e)
    {
        ...
    }
}

To fix the violation, the custom delegate declaration is removed and generic version of EventHandler is used:

public class EventProducer
{
    public event EventHandler<CustomEventArgs> CustomEvent;
}
 
public class EventConsumer
{
    public void AttachEvent(EventProducer producer)
    {
        producer.CustomEvent += new EventHandler<CustomEventArgs>(ProcessEvent);
    }
 
    private void ProcessEvent(object sender, CustomEventArgs e)
    {
        ...
    }
}

You may say it is not a big deal, whether to use custom delegate or template version of EventHandler. But that statement is true about generics at large – generics introduction in .NET 2.0 is mostly about more concise and more elegant (and as a consequence, more easily understood and maintainable) code. Using generic event handler instead of custom ones is yet another small step towards this goal.

Related posts
- Design CA1009 DeclareEventHandlersCorrectly
- Performance CA1810 InitializeReferenceTypeStaticFieldsInline
- Performance CA1822 MarkMembersAsStatic

No comments: