In .NET Events (Part 1 – A Refresher) we covered how events work, and how to publish and subscribe to them.? Now that we all agree how great and easy events are, lets talk for a moment about the 800 lb. gorilla in the room – you know, the one we were supposed to never have to talk about with .NET – memory management.? If you remember from our refresher, events are essentially a collection of method pointers.? These method pointers have to know the object instance they are operating on so that different instances of the same class can selectively subscribe to different events without having to handle the ones they are not interested in.? So that means that somewhere under the hood events must be holding a reference to the specific subscription instance, in addition to the appropriate method.
Sure enough, if you are curious, you can treat the event just like you would any other variable instance, and access its various members.? By default, all events are MultiCastDelegates.? This means that they hold multiple delegates, which you can access by calling the “GetInvocationList” method.? This returns an array of delegates which you can use to see who is actually subscribed to your event at any given time.? You can also see that each delegate keeps a reference to the target object.? I am going to update the classes and methods we created in Part 1 to demonstrate how you might use this information to display a list of subscribers:
??? this.EmptyArgumentPublished(this, EventArgs.Empty);
Of course, there is a specific pattern that you should use to avoid a NullReferenceException being thrown (and to avoid a race-condition), but I will get to that a little later.? For now, it is useful to think of events as methods.
Subscribing
Subscribing to an event is even easier than publishing one.? All you need to do is define a method with an appropriate signature and then add it to the publisher's event:
????? publisher.EmptyArgumentPublished += this.HandleEmptyArgumentPublished;
????? // Alternatively you can use the fully qualified way (required in older versions of .NET)
????? publisher.EmptyArgumentPublished += new EventHandler(this.HandleEmptyArgumentPublished);
That's all there is to it.? You are now subscribed to the event.? This assumes of course that the method “HandleEmptyArgumentPublished” has the correct signature.? When you no longer wish to subscribe to this event, you can unsubscribe just as easily:
????? publisher.EmptyArgumentPublished -= this.HandleEmptyArgumentPublished;
????? // Alternatively you can use the fully qualified way (required in older versions of .NET)
????? publisher.EmptyArgumentPublished -= new EventHandler(this.HandleEmptyArgumentPublished);
In this case, the event will do a value-based comparison (as opposed to a reference-based) to determine which handler to remove, so you do not have to keep the original instance of the EventHandler that you created.
Best Practices
I glossed over quite a bit in my quick little introduction to events, so lets go back to the beginning and implement a slightly more complicated event.? The first thing to realize is that since events are simply a collection of method pointers, you can technically use any method signature you desire to define an event.? However, in .NET it is expected that all event delegates will have a signature with 2 parameters, where the first is an object and represents the instance that fired the event, and the second parameter is the actual event arguments and derives form the “EventArgs” class.? This still gives you incredible flexibility in the events you can create, but it does mean that creating a custom event requires a little bit more work.? Fortunately, with .NET 2.0 generics, they have made it a little bit easier.? The first thing that is required when creating a custom event is to create a new argument class.? By convention, this class should derive from the base “EventArgs” class and the name of the class should end in “EventArgs”.
Code In Review is proudly powered by
WordPress
Entries (RSS)
and Comments (RSS).