Delegates Part 11
Delegates Part 11
This method
begins by constructing a Set object, telling it to create an array of five objects. ProcessItems is called,
passing it null for its feedback parameter. This is the first example of how to use delegates. ProcessItems
represents a method that performs some action for every item managed by Set. Since the feedback
parameter is null in this example, each item is processed without calling any callback methods.
For the second example, a new Set.Feedback delegate object is constructed. This delegate object
is a wrapper around a method, allowing that method to be called back indirectly via the wrapper. To the
Feedback type's constructor, the name of a method, App.FeedbackToConsole in this example, is passed;
this indicates the method to be wrapped. The reference returned from the new operator is then passed
to ProcessItems. Now, when ProcessItems executes, it will call the App type's FeedbackToConsole
method for each item in the set. FeedbackToConsole simply writes a string to the console indicating
which item is being processed and the value of that item.
The third example is really identical to the second one. The only difference is that the Feedback
delegate object wraps the App.FeedbackToMsgBox method. FeedbackToMsgBox builds a string
indicating which item is being processed and the value of that item. This string is then displayed in a
message box.
The fourth and final example demonstrates how delegates can be linked together to form a chain.
In this example, a reference variable to a Feedback delegate object, fb, is created and initialized to null.
This variable points to the head of a linked list of delegates. A value of null indicates that there are no
nodes in the linked list. Then, a Feedback delegate object is constructed that wraps a call to App's
FeedbackToConsole method. The C# += operator is used to append this object to the linked list
referred to by fb. The fb variable now refers to the head of the linked list.
Finally, another Feedback delegate object is constructed that wraps a call to App's
FeedbackToMsgBox method. Again, the C# += operator is used to append this object to the linked list,
and fb is updated to refer to the new head of the linked list. Now, when ProcessItems is called, it is
passed the head of the linked list of Feedback delegates. Inside ProcessItems, the line of code that calls
the callback method actually ends up calling all of the callback methods wrapped by the delegate objects
in the linked list. In other words, for each item being iterated, FeedbackToConsole will be called,
immediately followed by FeedbackToMsgBox. I will explain exactly how delegate chain works in my next
column.
It is important to note that everything is type-safe in this example. For instance, when constructing a
Feedback delegate object, the compiler ensures that App's FeedbackToConsole and
FeedbackToMsgBox methods have the exact prototype, as defined by the Feedback delegate. That is,
both methods must take three parameters (Object, Int32, and Int32) and both methods must have the
same return type (void). If the method prototypes don't match, then the compiler will issue the following
error message: "error CS0123: The signature of method 'App.FeedbackToMsgBox()' does not match this
delegate type."
So far I've discussed how to use delegates to call static methods. However, delegates can also be
used to call instance methods for a specific object. For instance methods, the delegate needs to know the
instance of the object that is to be operated on by the method.
An event can be used as the left operand of the += and -= operators. These operators are used,
respectively, to attach event handlers to, or to remove event handlers from an event, and the
access modifiers of the event control the contexts in which such operations are permitted.
The only operations that are permitted on an event by code that is outside the type in which that
event is declared, are += and -=. Therefore, while such code can add and remove handlers for
an event, it cannot directly obtain or modify the underlying list of event handlers.
In an operation of the form x += y or x –= y, when x is an event the result of the operation has
type void (§12.21.5) (as opposed to having the type of x, with the value of x after the
assignment, as for other the += and -= operators defined on non-event types). This prevents
external code from indirectly examining the underlying delegate of an event.
Example:
The following example shows how event handlers are attached to instances of the Button class:
public LoginDialog()
{
okButton = new Button(...);
okButton.Click += new EventHandler(OkButtonClick);
cancelButton = new Button(...);
cancelButton.Click += new EventHandler(CancelButtonClick);
}
When the compiler sees the previous line, it actually defines a complete class definition that looks
something like the code in Figure 2.