|Multicast Delegates and Events|
|Written by Mike James|
|Friday, 24 June 2016|
Page 1 of 3
Multicast delegates are useful in their own right but they also form the basis on which the C# event system is built. We take a close look at how they work and how to use them. For example, did you know you could add and subtract delegates?
This is a chapter of our ebook on C# - a work in progress.
A delegate is a class that wraps a method so that it can be used in more sophisticated ways - e.g. passed as a parameter to another method. But delegates are also ways of making lists of methods that can be called in sequence when the delegate is invoked. Now that you know how delegates work its time to look at the multicast delegate and their relationship to events.
If you look at the Framework Reference you will find a Delegate class and a class derived from it, MulticastDelegate.
In theory the Delegate class can encapsulate a single method and the MulticastDelegate maintains a list of methods and so can encapsulate more than one method.
In practice this isn’t true.
Early on in the development of the framework it was decided that Delegate and MulticastDelegate should do the same job and be merged. However merging them would have created too many problems so Delegate was left as the base class for MulticastDelegate, but the two are essentially identical.
At this point you might imagine that you would never use the Delegate class but in fact it is still returned by some methods that expect to return a single method encapsulated by a Delegate.
It also used to be the case that if you created a delegate which returned void then it was encapsulated by a MulticastDelegate but if it returned a result then a Delegate was used.
This distinction was made because of the difficult of determining which method’s return value was actually returned in a multicast invocation. However, this was solved by simply encapsulating all methods using MutlicastDelegate and in a multicast situation the last method called is the only one that returns a result.
All delegates are MulticastDelegates but for efficiency reasons an invocation list is only created if there is more than one method encapsulated.
That is, a delegate that encapsulates a single method stores this method in its Method and Target properties and has a null invocation list.
Both of these classes are abstract and you cannot instantiate either directly – but this doesn’t mean that they aren’t of use as is explained below.
In normal use it is up to the compiler to create instances of a delegate class appropriate to encapsulate a method. Exactly how this is done can vary according to the .NET language in use.
In C# the delegate keyword creates an instance not of the Delegate class but of the MulticastDelegate class.
That is, in C# an instance of a delegate type is always an instance of a MulticastDelegate which extends the basic Delegate class to include an Invocation list which can store multiple methods.
Multicast in action
The easiest way to follow this confusing situation is to try it all out.
First we need two methods with the same signature that we can encapsulate in a suitable delegate:
A suitable delegate type is just:
Now we can create an instance of MulticastDelegate encapsulating two methods:
The += operator is overloaded to add a method to the invocation list and this should be familiar to you if you have hand-coded events.
Invoking the delegate is just the same if it has single or multiple methods:
If the invocation list contains multiple methods then these are called in the order that they were added. Any parameters are passed to each method in turn and the final method to be called returns a value.
That is, in this case the Hello method is called with its parameter set to “delegates” then Goodbye is called with the same parameter. Only Goodbye returns a result and hence i is set to 2.
You can use anonymous methods or lambda expressions to define delegates within multicast delegates.
Or, more properly if you agree that lambda expressions should be used in preference to anonymous methods:
Notice that any unhandled exceptions that are raised by the delegates in the invocation list brings the call sequence to an end.
|Last Updated ( Friday, 29 July 2016 )|