Intercepting Add and Remove of C# Event Delegates

Save/Share Google Yahoo! Digg It Reddit del.icio.us
My Zimbio

All you geniuses and rocket scientists out there probably already know this, but I just stumbled on it, and I think it’s kind of cool. Did you know you can customize the adding and removing of C# event handlers? I didn’t.

I’m going to end this post with the question “Yes, but what’s it good for?” You folks with the Ph. D. in C#, feel free to scroll to the bottom and post your answers. For my fellow mortals out there, let me recap what I’m talking about.

We all know how to declare events on a class, right? It goes something like this:

using System;

namespace AddRemoveDelegates

{

public class Account

{

private decimal balance;

public event EventHandler<EventArgs> Overdrawn;

public decimal Balance

{

get { return balance; }

set { balance = value;}

}

public void UpdateBalance(decimal amount)

{

balance += amount;

if (balance < 0)

{

if (Overdrawn != null) Overdrawn(this, EventArgs.Empty);

}

}

}

}

Straightforward, right? If the account balance goes below zero, we fire the Overdrawn event. We hook up listeners to the event like this:

using System;

namespace AddRemoveDelegates

{

class Example

{

public static void account_Overdrawn( object sender, EventArgs e )

{

Console.WriteLine(“Account is overdrawn”);

}

public static void Main(string[] args)

{

Account account = new Account();

// hookup the event listener

account.Overdrawn += account_Overdrawn;

account.UpdateBalance(-10);

}

}

}

For the most part, it’s as easy as that. But, have you ever wondered just what magic is going on inside that call to += ?

Take a moment to consider the Balance property on the Account class we defined above. How do we access it? Well, first we have to back it up with a private field (named balance with a lowercase “b”). Then, we define get and set implementations to control how the private field is accessed and altered. They teach that in Day 1 of a C# programming class.

event members work largely the same way, except the compiler does some work behind the scenes on your behalf. When you declare an event, the compiler gives you a hidden MulticastDelegate field that manages a collection of event listeners. The += and -= operators are implemented to add and remove the handlers from the hidden delegate.

However, you have the ability to explicitly implement your own behavior for += and -= using the keywords add and remove, respectively, just as properties use get and set.

Here’s an alternate implementation of the Account class:

using System;

namespace AddRemoveDelegates

{

public class Account

{

private decimal balance;

// we have to explicitly declare a MulticastDelegate

private EventHandler<EventArgs> onOverdrawn;

// here, we control the adding and removing of listeners

public event EventHandler<EventArgs> Overdrawn

{

add

{

onOverdrawn =

(EventHandler<EventArgs>)Delegate.Combine(onOverdrawn, value);

}

remove

{

onOverdrawn =

(EventHandler<EventArgs>)Delegate.Remove(onOverdrawn, value);

}

}

public decimal Balance

{

get { return balance; }

set { balance = value;}

}

public void UpdateBalance(decimal amount)

{

balance += amount;

if (balance < 0)

{

// we also have to invoke the delegate through the field, now

if (onOverdrawn != null) onOverdrawn(this, EventArgs.Empty);

}

}

}

}

We’ve added a private field of type EventHandler<EventArgs> called onOverdrawn. EventHandler<EventsArgs> is a subtype of System.MulticastDelegate, and this will be our collection of registered event listeners. We’ve also created add and remove implementations for the Overdrawn event. Using static methods Combine and Remove on the Delegate class, we can update the listeners in our MulticastDelegate.

We haven’t gained anything, yet. This is what C# would otherwise give us for free. But, think about the possibilities! Yes! The possibilities!

What possibilities?

Yes, but what’s it good for?

When the only tool you have is a hammer, every problem looks like a nail — and this is a really cool hammer. It’s got what I call “geek appeal”. It’s a clever trick to show other developers so they can bow at your genius. Unfortunately, I’m kind of at a loss for a legitimate use — except maybe for some contrived examples.

I don’t like creating side effects in what is traditionally a simple and well understood concept — the Observer Pattern. Making code do something unexpected is likely to confound clients of your class unless the behavior is very narrow and contained in scope. Why solve a problem by injecting specialized behavior into event management when you can solve it somewhere else?

Okay, logging the adding and removing of listeners might make sense. Perhaps even supporting thread synchronization would make sense (you might want to prevent changes in the MulticastDelegate while an event is in the middle of firing).

Still, it seems like something a junior programmer would do just to show off – but unwittingly invite trouble at the same time.

What do you think? Have you used this before? Can you envision any problems where custom event listener management is the ideal solution?

Save/Share Google Yahoo! Add to Technorati Favorites Digg It Reddit
del.icio.us My Zimbio

16 Responses to “Intercepting Add and Remove of C# Event Delegates”

  1. ChrisJ Says:

    See http://msdn.microsoft.com/msdnmag/issues/06/11/NETMatters/ for some suggested uses of this feature.

  2. HM Says:

    I *hoped* that if I made the custom multicast delegate protected instead of private as you have it, then it would eliminate the problem where an event defined in a base class can’t be raised by a derived class. But it didn’t work. Then I realized something seemed to be missing in your code anyway–while you show how to have += and -= add handlers to the custom list instead of to the private default list, I don’t see anything that tells the application, when you *raise* the event, to call the handler or handlers that are on the custom list rather than continuing to look for them on the default list.

  3. Mike Gavaghan Says:

    There’s nothing missing. You don’t need to write it because it’s handled for you by .NET. The call to Delegate.Combine() is what builds up the list of handlers into a multicast delegate encapsulated by an EventHandler subtype. It’s that implementation of EventHandler that calls all of the handlers previous registered.

    Remember, all we’re doing here is intercepting the calls to add and remove handlers. Actually invoking the handlers when an event is raised is still handled by the framework.

    You *could*, if you wanted to, simply add all of your handlers to an ArrayList and not use Delegate.Combine() at all. Then, you could write a custom implementation that iterates over all of the registered handlers (I think that’s the part you thought was missing). That’s a very obscure scenario (perhaps you need to ensure your handlers are called in a particular order). I’d make sure it’s really necessary before having to test and maintain that code.

    Good luck. Let me know how it turns out.

  4. Doron Assayas Says:

    It’s a useful pattern in proxy classes where the proxy relays message broadcasts (that come in over TCP, for example) as events. I intercept the add/remove to notify the server whether it needs to broadcast a certain type of messages (no handlers means no need to broadcast, saving bandwidth).

  5. Hank Hatch Says:

    The main purpose of this is really the following:
    In C++ we basically had to manage our own lists of function pointers (callbacks) in order to provide for notifications.
    In visual basic we had events built in.
    So in order to make events easier and more modern and acceptable (probably to convert more VB programmers into C# programmers) events had to be a language feature.
    Type safe function pointers (delegates) are used to make this possible.
    Built into delegates have invokation lists.
    Enter managed code and garbage collection.
    Enter you as a component developer.
    If you do not declare your delegate as a private member of your class then YOU cannot access it’s invokation list.
    If you only declare the event public (and therefore do not have a property) then you are limited by the compiler to the access of that field.
    The documentation states that the keyword event limits access to the delegate to using the binary += and -+ operators.
    So long story short is this.
    Considering the keyword “event” exists is NO excuse to be irrisponsible in coding and lazy.
    Not using this pattern is somewhat the same as being irrisponsible with your pointers in a non managed environment.
    It is similar to NOT calling delete or not creating a “smart pointer” type situation where you bind delete, removing of a reference counter, and the setting to null all in one step.
    What I am saying is this.
    If you are going to code a component that offers many events and design that component so that it is going to be heavily used then you don’t want to subject every single one of you clients to surviving generation 1 garbage collection.
    If you offer an event and you have subscribers even if this goes out of scope your hidden non accessible invokation lists all still have references to you old clients. They will then NOT be released from garbage collection as soon as they could be. If you combine structures like this in algorithms that utilize a high number of objects or lots of stack space then you are coding yourself into the situation that you do not have the EXPLICIT unbinding of objects in object graphs so that your component can be used in many situations.

    Basically this is another way to say it. If your component offers events it is better to also offer IDisposable so that the client code can decide how things are handled. Create a private delegate. Create a public event so clients can subscribe to the notification with the += and -+ operators they are used to. But now VERY important -> in your Dispose enumerate the private delegates invokation list and remove the references to the clients. This is a “TearDown” and the same thing WAS necessary in VB 6 for certain situations (pointers to parent objects in collections as an example with a COM reference counting systems).

    This way you can better control and increase the number of objects that will be freed during a lower generation of garbage collection.

    Remember just because it is C# and managed code DOES NOT mean you cannot have a memory leak. If you want to expand an object oriented language with “out-going calls” or “events” which is basically implemented with circular referencing then be aware that just because something was automated for you DOES NOT mean you can’t get in trouble.

    Keep the private delegate for anytime you feel you need to control the members of the invokation list. I have been stressing just the garbage collection and memory leak but there are other patterns. Use it when you want to dump the list and require new subscriptions from within a server or singleton periodically. Often templating out this pattern without the dispose is my preference NOT because I want to show people what I know but because I want to somewhat document that depending on how my object is used a refactor should take place which includes some code in here. That is not obvious with the use of the public event field.

  6. Hank Hatch Says:

    Also it is more of a direct wrap to do it like this ->

    private StateMachineEventHandler canTransition;
    public event StateMachineEventHandler CanTranistion
    {
    add { this.canTransition += value; }
    remove { this.canTransition -= value; }
    }

    which is pretty darn simple considering the power it can give you.

  7. Cosmin Onea Says:

    http://www.cosminonea.net/2008/12/10/Subsonic30AndAPossibleSerializationProblem.aspx

    This may be one possible good usage.

  8. jgr4 Says:

    Thanks for the post. One usage is for debugging. I couldn’t figure out where handlers were getting added and why there seemed to be to many. This technique allows you to put a breakpoint or a Debug.WriteLine in the add {}.

  9. Levi Says:

    Actually, the most common reason to implement an add & remove on an event is for memory consumption. For instance, let’s say you have a type which has a large number of events. If those events are defined with just a public event field, then the type has to allocate store for each delegate, even if no one is subscribed to the event.
    For instance, if the type has 15 events, then when you create an instance of the object, it will have 15 pointers to delegates. Most of the events will be null.
    Now, if we change the type to use add and remove and implement the add and remove like so:
    public EventHandler Click
    {
    add
    {
    eventList.Add(ClickKey, value);
    }
    remove
    {
    eventList.Remove(ClickKey, value);
    }
    }

    Where eventList is an EventHandlerList, then your type only needs one reference to track all of it’s events instead of 15. If an event is never subscribed to, then it creates no overhead. While the field approach would always require a null pointer.

    Btw, add and remove aren’t the only accessors supported by the .net framework. C++ allows you to also define the raise accessor, but it’s not allowed in C#.

  10. Zachary Says:

    Echoing what Hank Hatch says below, using this direct wrap function enables you to wrap built in .NET classes like BackgroundWorker and abstract an Interface for testing purposes (ie generating mocks etc) and using the Decorator Pattern (ref Head First Design Patterns).

    Hank Hatch Says:

    November 3rd, 2008 at 11:46 am
    Also it is more of a direct wrap to do it like this ->

    private StateMachineEventHandler canTransition;
    public event StateMachineEventHandler CanTranistion
    {
    add { this.canTransition += value; }
    remove { this.canTransition -= value; }
    }

    which is pretty darn simple considering the power it can give you.

  11. Hi Vis Jacket Says:

    A lot of good feedback on this article, thanks to everyone for sharing. Just like most things with Windows, there is more than 1 way to do things. More than 1 way to skin a cat, I suppose. ;D

    I don’t have the need to dig further under the hood, so the += and -= operators work just fine for our every day applications, but it’s nice to know we can expand on that if needed.

  12. Brij Sharma Says:

    I always use += and -= to manage adding and removing event handlers.
    To explicitly do it in your code is something which I don’t think is required but like in the topic above is good to show off.

  13. Jorge Says:

    What it is good for? weak event handlers…

    http://diditwith.net/PermaLink,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx

  14. Marc Gravell Says:

    Firstly, you don’t need to use Combine; += and -= work fine (the same as how, with strings, + is implemented via string.Concat).

    Typical uses:

    – sparse events via EventHandlerList
    – event proxying

    Also, note that the compiler-generated boilerplate is thread-safe, but the code here *is not*. S basically, the simpler “field-like event” version should be used by default (in preference to adding a delegate backing field).

    With regards the comment about serialization: that can be handled too, by using the “field:” prefix on an attribute, for example:

    [field:NonSerialized] public event EventHandler SomeEvent;

  15. Bruno Oliveira Says:

    This actually seams to solve me a problem easily…i didn’t tried yet but here it is:

    This is the scenario:

    I have a shared proxy, lets call this PROXY1, that subscribes an event of a third-party component WORKER1, and I have multiple clients listening on PROXY1 events.

    This is the problem:

    I need to free PROXY1 through Garbage collector finalizer, I can’t dispose it by calling Dispose() because I don’t known when all clients are finished using the PROXY1 events.

    Solution:

    Implement explicitly add, remove of PROXY1 events, and when listeners = zero unsubscribe the WORKER1 event, if listners != zero subscribe WORKER1 event.

    Garbage collector will collect PROXY1 when no references points to it, and that happens when it unsubscribes WORKER1 event.

  16. Simon Miller Says:

    well, you asked for geeky responses, and that’s what you got! But no one really gave personal legitimate use of it, if you ask me – just examples of how you might want to or could use such code. We then get side-tracked into the “is it safe?” line of questioning.

    So I have found myself in a real world scenario, looking for this very answer, so I don’t have to try and work it out. It’s as easy as I hoped it would be, so let me explain. I guess it comes under the “event proxying” category.

    I have a project that loads other projects (dll’s) at runtime, as a kind of plug-in mechanism.
    The loaded DLL needs to expose an event to the project that loaded it. Internally for the loaded project, where it’s exposed to the “loader” – the event must exist, but the implementation of that event is actually burried 3 levels deeper in. The point is, I don’t want to implement an event at each level to “bubble up” the event until it finally hits the “loader”.

    Why? Efficiency! It’s a time-critical piece of code, and I don’t want bubbling of one event handler into another, until it reaches the desired end target.

    Instead, I want to capture when an event is being subscribed to – and use what I’m visualizing as a “wormhole” (method chain to the layer handling the event) which takes the delegate, and adds it to the event handler at the level it will be raised. Thus, avoiding the long trip of bubbling the events every time they happen.

    not implemented it yet, but I will now! thanks for the code snippet.

Leave a Reply