EventHandlerList - Declaring .Net Events that Conserve Memory

Ever heard of the EventHandlerList object that lives in the System.ComponentModel namespace of the .Net framework?  I hadn't until I disassembled the System.Windows.Forms.Control class while debugging the other day.  I did a few google searches and ended up on an MSDN page titled 'How to: Declare Events That Conserve Memory Use'.  I found the content rather interesting. 

Typically, a class declares an event as follows:

public class Book
{
    public event EventHandler PagedChanged;

    public void TurnThePage()
    {
        if (this.PagedChanged != null)
        {
            this.PagedChanged(this, EventArgs.Empty);
        }
    }
}

According to the MSDN documentation, when declared like this, the compiler will automatically add a delegate field to the class to store the event information.  This field takes up memory even if the event is never used.  As a result, if a class contains a large number of unused events - memory can be needlessly wasted.  To work around this, the article recommends using event properties to explicitly manage adding and removing event subscriptions.  Because the class is explicitly implemeting the event properties, the compiler will not inject the delegate fields into the class.  This way, memory is only allocated for the events that are being used - a type of 'pay as you go' approach.

Here is the same class re-written using event properties and the EventHandlerList.  Event information is accessed from the EventHandlerList via an event key (A related MSDN article discusses this approach as well and recommends using a static readonly object as the event key; the dissassembled Control class follows this pattern as well, so that is what I used here).

public class Book
{
    private static readonly object PageChangedEventKey = new object();
    private EventHandlerList _events = new EventHandlerList();

    public event EventHandler PagedChanged
    {
        add { this._events.AddHandler(Book.PageChangedEventKey, value); }
        remove { this._events.RemoveHandler(Book.PageChangedEventKey, value); }
    }

    public void TurnThePage()
    {
        EventHandler pageChanged = this._events[Book.PageChangedEventKey] as EventHandler;
        if (pageChanged != null)
        {
            pageChanged(this, EventArgs.Empty);
        }
    }
}

Out of curiosity, I viewed the IL for both of these implementations of the Book class, and sure enough for the first sample a backing field was generated for the PageChanged event while for the second sample there wasn't one, but there were fields for the EventHandlerList object as well as the PageChangedEventKey object.  The article is a little vague about when this approach should be used (it only says 'There are several circumstances when it is important that an application keeps its memory usage low.'), but I assume classes that declare many events that under normal conditions are often unused would make prime candidates.


TrackBack

TrackBack URL for this entry:
http://mattberseth.com/blog-mt/mt-tb.fcgi/32

Listed below are links to weblogs that reference EventHandlerList - Declaring .Net Events that Conserve Memory:

» EventHandlerList - Declaring .Net Events that Conserve Memory from DotNetKicks.com
You've been kicked (a good thing) - Trackback from DotNetKicks.com [Read More]

Comments


Regarding your last assumption: This approach should be used if the number of events exceeds the usually registered number of event handlers notably. Also there should be enough events involved to compensate for the additional overhead EventHandlerList implies.
The typical examples are windows controls or web controls - many events, almost all never used.
In other words: spare the effort if youve got less than half a dozen events (and how often do you have more?).

I usually use strings as keys (need to be declared as const, a literal wont do). If you look at the EventHandlerList during debugging, an object reference wont tell you anything, a string does. And by the way: "usually" stands for "in the two or three cases I actually had to (or rather could) use EventHandlerList".

Hi.
Very interesting site!
Thanks!

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)