Leveraging the EventHandler<T> delegate more effectively

If you are now coding in .Net 2.0/3.0/3.5 and are creating types that expose events. Chances are you have started leveraging the EventHandler<T> delegate that frees you from creating custom delegate signatures for events anymore. If not this post is for you. Let’s say that you want to expose an event that another object could consume. Normally you would follow these steps:

  1. Create a type that inherits from EventArgs if the event is going to propagate event specific data. This step is optional as you may not have any custom data to propagate.
  2. Create a delegate signature for the event. If you are not using a custom EventArgs derivative, then you can get away with just leveraging the EventHandler delegate that already exists in the framework.
  3. Create the type that is going to raise the event and have it declare the event using either implicit or explicit event registration.
  4. Create a method on the type that will raise the event.

In .Net 2.0/3.0/3.5 these steps can now become:

  1. Create a type that inherits from EventArgs if the event is going to propagate event specific data. This step is optional as you may not have any custom data to propagate.
  2. Create the type that is going to raise the event and have it declare the event using either the EventHandler delegate type for an event that does not propagate custom data, or leverage the generic EventHandler<T> delegate to declare an event bound to the specific EventArgs derivative you need to use. Again you can use either implicit or explicit event registration.
  3. Create a method on the type that will raise the event.

This can actually become slightly better. Instead of always creating a class that derives from EventArgs if you need to pass custom data; create a parameter object that encapsulates the information you would want to propagate in the event. This class does not need to inherit from EventArgs. Then create the following utility class:

 

public class EventArgs<T> : EventArgs { private T eventData; public EventArgs(T eventData) { this.eventData = eventData; } public T EventData { get { return eventData; } } }

This means that the 3 steps above can now be changed to:

  1. Create a parameter object that encapsulates any information you want to propagate in the event.. This step is optional as you may not have any custom data to propagate.
  2. Create the type that is going to raise the event and have it declare the event using either the EventHandler delegate type for an event that does not propagate custom data, or leverage the generic EventHandler<T> delegate, with the generic EventArgs<T> class to declare an event bound to the specific parameter object you need to use. Again you can use either implicit or explicit event registration.
  3. Create a method on the type that will raise the event.

 

So if I had a parameter object that looked like this:

public class ReportingPeriod { private DateTime start; private DateTime end; public DateTime Start { get { return start; } } public ReportingPeriod(DateTime start, DateTime end) { this.start = start; this.end = end; } }

I would be able to create a type that raises an event to propagate this data as follows (using implicit registration):

public class ReportTrigger { public event EventHandler<EventArgs<ReportingPeriod>> RunReport; }

Or using explicit registration:

public class ReportTrigger { private EventHandler<EventArgs<ReportingPeriod>> subscribers; public event EventHandler<EventArgs<ReportingPeriod>> RunReport { add { subscribers += value; } remove { subscribers -= value; } } }

Develop With Passion!

This entry was posted in .Net 2.0, .Net 3.0, C#, Featured. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

4 Responses to Leveraging the EventHandler<T> delegate more effectively

  1. Eric Swanson says:

    This is fantastic! This starts looking horrible in VB.NET when I used a generic List(Of String). Check out all the parenthesis! Woo hoo!

    Dim eventData As New List(Of String)
    New EventArgs(Of List(Of String))(eventData)

    Public Class EventArgs(Of T)
    Inherits EventArgs

    Private _eventData As T

    Public Sub New(ByVal eventData As T)
    MyBase.New()
    _eventData = eventData
    End Sub

    Public ReadOnly Property EventData() As T
    Get
    Return _eventData
    End Get
    End Property
    End Class

    I prefer the C# equivalent:
    List eventData = new List();
    new EventArgs >(eventData);

  2. JP says:

    @Mobocracy,

    I am not sure why you would want to pass an event handler delegate across a wcf boundary.

    JP

  3. Mobocracy says:

    Can this cross a wcf boundry ? It’s my understanding that untyped objects can not cross a wcf boundry.

  4. Very interesting article.From my point of view the class EventArgs can be changed in this way :
    class EventArgse
    :EventArgs where T:new()
    {

    private readonly T eventData;
    // Fields
    public new static readonly EventArgse Empty;

    static EventArgse()
    {
    Empty = new EventArgse();
    }
    private EventArgse()
    {

    }
    public EventArgse(T eventData)
    {
    this.eventData = eventData;
    }

    public T EventData
    {
    get { return eventData; }
    }
    }

    As you see I just implemented Null pattern.

Leave a Reply