Now it's time to take one step closer to using events to implement Observer. In the last lesson, we were introduced to delegates and were able to use them to remove some of the work of implementing Observer. However, the implementation still required us to maintain a list of the delegates that needed to be called. In this lesson, we'll discuss a way to let .NET maintain this list for you, and write even less code to implement the Observer pattern.
The .NET designers built a feature into delegates that makes imlpementation of the Observer pattern much easier. A multicast delegate looks just like any other delegate when you are writing code, but it is actually a list of delegates. You can add and remove delegates to a multicast delegate, and when you invoke the multicast delegate it will automatically call every delegate in its list.
There's nothing different about how you create and use multicast delegates compared to
normal delegates. The only difference is you use the static method
Delegate.Combine
to add a delegate to the list and the
Delegate.Remove
method to remove a delegate from the list. In VB,
Delegate
is a keyword, so to actually call the methods you'll
have to use the [] brackets to escape the class name:
[Delegate].Combine(...) [Delegate].Remove(...)
A neat feature of Combine
is it doesn't care if the delegate is currently
null (Nothing) or empty; it will always return at least a 1-item multicast
delegate. Likewise, Remove
doesn't behave badly when the delegate is null or
doesn't contain the delegate you want to remove. When you invoke a multicast delegate, it
will call every delegate in its list. Now that we've reviewed multicast delegates, let's
take a look at how we'll use them.
If you compare the WeatherStationWithMulticastDelegates
project to the one used
in the previous lesson, you'll find that there's only a few minor changes. Take a look at
TemperatureSensor
. Instead of maintaining a list of callbacks, not it has
a field _updateCallback
of type UpdateCallback
.
AddCallback
and RemoveCallback
use the appropriate
Combine
or Remove
method to add/remove callbacks to the multicast
delegate _updateCallback
. OnTemperatureUpdated
no longer needs to loop: it simply invokes the multicast delegate and lets .NET do the work
of calling everything in the list.
This was a remarkably short article because multicast delegates aren't used much differently
than normal delegates. While it's true that we didn't have to manually maintain a list any
more, we still had to provide the AddCallback
and RemoveCallback
methods. Wouldn't it be nice if something handled all of that for us?
There's one small gotcha with multicast delegates. Since you aren't looping over the
methods yourself, you aren't in control of what happens when something goes wrong. If one
of the delegates throws an exception and it isn't handled, none of the delegates that come
after that one in the list will be executed. You can hack around this by using the
GetInvocationList
method to get the list, manually iterate, and handle
excptions that are thrown. Think long and hard before doing this, though. Since you tend
to use delegates to allow users to hook their code into yours, you can't reasonably
guarantee that you can appropriately handle all exceptions they might through. It's best
to stick to the general guideline that delegate callback methods should avoid throwing
exceptions.