You can think of a delegate as an object that holds one or more methods. Normally, of course, you wouldn’t think of “executing” an object, but a delegate is different from a typical object. You can execute a delegate, and when you do so, it executes the method or methods that it “holds.”
In this article let’s analyse the syntax and semantics of creating and using delegates. We’ll start with the example code on the next page. Don’t worry if everything isn’t completely clear at this point, because we’ll explain the details of delegates throughout the rest of the chapter.
• The code starts with the declaration of a delegate type called MyDel. (Yes, a delegate
type—not a delegate object. We’ll get to this shortly.)
• Class Program declares three methods: PrintLow, PrintHigh, and Main. The delegate
object we will create shortly will hold either the PrintLow or PrintHigh method—but
which one will be used won’t be determined until run time.
• Main declares a local variable called del, which will hold a reference to a delegate
object of type MyDel. This doesn’t create the object—it just creates the variable that
will hold a reference to the delegate object, which will be created and assigned to it
several lines below.
• Main creates an object of the .NET class Random, which is a random-numbergenerator
class. The program then calls the object’s Next method, with 99 as its input
parameter. This returns a random integer between 0 and 99 and stores that value in
local variable randomValue;.
• The next line checks whether the random value returned and stored is less than 50.
(Notice that we’re using the ternary conditional operator here to return one or the
other of the delegate objects.)
–– If the value is less than 50, it creates a MyDel delegate object and initializes it to hold a reference
to the PrintLow method.
–– Otherwise, it creates a MyDel delegate object that holds a reference to the PrintHigh method.
• Finally, Main executes the del delegate object, which executes whichever method
(PrintLow or PrintHigh) it’s holding.
Because we’re using the random-number generator, the program will produce different values on different runs. One run of the program produced the following output:
An Overview of Delegates
Now let’s go into the details. A delegate is a user-defined type, just as a class is a user-defined type. But whereas a class represents a collection of data and methods, a delegate holds one or more methods and a set of predefined operations. You use a delegate by performing the following steps. We’ll go through each of these steps in detail in the following sections. whereas a class represents a collection of data and methods, a delegate holds one or more methods and a set of predefined operations. You use a delegate by performing the following steps. We’ll go through each of these steps in detail in the following sections.
1. Declare a delegate type. A delegate declaration looks like a method declaration,
except that it doesn’t have an implementation block.
2. Declare a delegate variable of the delegate type.
3. Create an object of the delegate type and assign it to the delegate variable. The
new delegate object includes a reference to a method that must have the same
signature and return type as the delegate type defined in the first step.
4. You can optionally add additional methods into the delegate object. These
methods must have the same signature and return type as the delegate type
defined in the first step.
5. Throughout your code you can then invoke the delegate, just as it if it were
a method. When you invoke the delegate, each of the methods it contains is
In looking at the previous steps, you might have noticed that they’re similar to the steps in creating and using a class. Figure 14-1 compares the processes of creating and using classes and delegates.
You can think of a delegate as an object that contains an ordered list of methods with the same signature
and return type, as illustrated in below figure.
• The list of methods is called the invocation list.
• Methods held by a delegate can be from any class or struct, as long as they match
both of the following:
–– The delegate’s return type
–– The delegate’s signature (including ref and out modifiers)
• Methods in the invocation list can be either instance methods or static methods.
• When a delegate is invoked, each method in its invocation list is executed.