Delegates Part 8

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 2

The StaticCallbacks method demonstrates the various ways of using callback delegates.

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."

Calling Instance Methods

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.
To understand how calling back an instance method works, take a look at the InstanceCallbacks
method in Figure 1. This code is extremely similar to the code for static methods. Note that after the Set
object is constructed, an App object is constructed. This App object doesn't have any fields or properties
associated with it and is created merely for demonstration purposes. When the new Feedback delegate
object is constructed, its constructor is passed appobj.FeedbackToFile. This causes the delegate to wrap
a reference to the FeedbackToFile method, which is an instance method (not static). When this instance
method is called, the object referred to by appobj is the object being operated on (passed as the hidden
this parameter). The FeedbackToFile method works like the FeedbackToConsole and
FeedbackToMsgBox methods except that it opens a file and appends the processing item string to the
end of the file.
Demystifying Delegates

On the surface, delegates seem really easy to use: you define them using the C# delegate keyword,
you construct instances of them using the familiar new operator, and you invoke the callback using
familiar method call syntax (except instead of a method name, you use the variable that refers to the
delegate object).
However, what's really going on is quite a bit more complex than what the previous samples illustrate.
The compilers and the common language runtime (CLR) do a lot of behind-the-scenes processing to hide
this additional complexity. In this section, I'll focus on how the compiler and CLR work together to
implement delegates. This knowledge will greatly improve your understanding of delegates and will teach
you how to use them efficiently and effectively. I'll also touch on some additional features that delegates
make available to you in your code.
Let's start by reexamining this line of code:

public delegate void Feedback(Object value, Int32 item, Int32 numItems);

When the compiler sees the previous line, it actually defines a complete class definition that looks
something like the code in Figure 2.

You might also like