Tom Goff's .Net Musings

Tidbits of information regarding .Net, C#, and SQL Server.

TOTW: Avoid Unnecessary EventArgs Allocations

leave a comment »

In a previous blog entry about the generic EventHandler delegate, I included an example similar to the following example:

public class MyObject {
    // ... Other code ...

    /// <summary>
    /// This event is fired when something happens.
    /// </summary>
    [field: NonSerialized]
    public event EventHandler<MyCustomEventArgs> SomeEvent;

    /// <summary>
    /// This method is used to fire the <see cref="E:SomeEvent"/>
    /// event.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The event arguments.</param>
    private void OnSomeEvent(Object sender,
        MyCustomEventArgs e) {
        if (null != SomeEvent)
            SomeEvent(sender, e);
    }
}

public class MyCustomEventArgs : EventArgs {
    /// <summary>
    /// Initializes a new instance of the
    /// <see cref="MyCustomEventArgs"/> class.
    /// </summary>
    /// <param name="whatHappened">What happened.</param>
    public MyCustomEventArgs(String whatHappened) {
        this.whatHappened = whatHappened;
    }

    /// <summary>
    /// Holds a string that tells what happened.
    /// </summary>
    private String whatHappened;

    /// <summary>
    /// Gets a string that tells what happened.
    /// </summary>
    /// <value>What happened.</value>
    public String WhatHappened {
        get {
            return this.whatHappened;
        }
    }
}

In general, most developers would include additional overloads of the OnSomeEvent method to make their lives easier. For example, the following overload of OnSomeEvent allows you simply provide the “what happened” text and the method handles everything else.

/// <summary>
/// This method is used to fire the <see cref="E:SomeEvent"/>
/// event.
/// </summary>
/// <param name="whatHappened">What happened.</param>
private void OnSomeEvent(String whatHappened) {
    OnSomeEvent(this, new MyCustomEventArgs(whatHappened));
}

The problem with the code above is that a new instance of MyCustomEventArgs is allocated even if SomeEvent is null. Eventhough, nobody is subscribing to the SomeEvent event, we are performing a memory allocation.

We can update our overload so that the memory allocation is only performed if someone is actually subscribing to the event.

/// <summary>
/// This method is used to fire the <see cref="E:SomeEvent"/>
/// event.
/// </summary>
/// <param name="whatHappened">What happened.</param>
private void OnSomeEvent(String whatHappened) {
    if (null != SomeEvent)
        SomeEvent(this, new MyCustomEventArgs(whatHappened));
}

Now, the allocation of MyCustomEventArgs is only performed if it’s needed. If this event is fired often and typically does not have any handlers hooked up, then we can remove any unneeded burdon on memory and the garbage collector. 

With the example above, the OnSomeEvent methods are private. If you are expecting your class to be extended, then you may want to make OnSomeEvent(Object, MyCustomEventArgs) protected/public and virtual. This allows derived classes to customize the behavior of the SomeEvent event. If we change OnSomeEvent(String) so that it calls the event directly (instead of calling OnSomeEvent(Object, MyCustomEventArgs)), then dervied classes would have to override this overload as well. If OnSomeEvent needs to be virtual, then it’s probably best not to make the change described here.

Advertisements

Written by Tom

November 1, 2007 at 7:49 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: