
.NET 1.1+C# Delegates
The fourteenth part of the C# Object-Oriented Programming tutorial explains how to add delegates to classes and programs. Delegates are used to provide references to methods that may be altered at run-time. They are also essential when creating events.
What is a Delegate?
A delegate is a special kind of object that holds a reference to a method. The delegate can be called as if it were any other method. However, when called, the underlying referenced method is executed. This simple layer of abstraction is useful because unlike a direct call, the method being used does not need to be known when writing the code. The reference is created at run-time and may be changed repeatedly throughout the life of the executing program.
NB: If you have previously used C++ function pointers then you will see many similarities between these and delegates. Unlike function pointers, C# delegates are object-oriented, secure and type-safe.
Multicasting
Delegates provide a useful facility known as multicasting. When a delegate is used for multicasting, two or more method references may be added to the delegate object. In this situation, a single call to the delegate function actually calls each of the added methods in turn. The combination of the referenced items is known as the invocation chain or invocation list.
Asynchronous Callbacks
Another interesting use of delegates is known as asynchronous callback. As a delegate is an object, it may be passed as a parameter or assigned as the value of a property. This allows a delegate to be created and passed to a long-running, asynchronous process. When the process has finished executing, the delegate can be called to indicate completion. Asynchronous callbacks are beyond the scope of this article.
Creating a Delegate
Syntax
To create a delegate, the delegate keyword is used as a prefix to the method's signature as follows:
delegate return-type name(parameters);
The return-type is the data type that will be returned from a method that is referenced by the delegate. The name is the name of the delegate and the parameters section contains the comma-separated list of parameters used when calling the delegate. The return-type and parameters form the signature of the delegate and this must match the signature of the method that is linked to it, though the reference method may be static or linked to a particular instance of a class.
Creating a Simple Delegate
To demonstrate the declaration and use of a simple delegate we will create a program as an example. To begin, create a new console application named "DelegateDemo". Add a class file named "Scoreboard" to the project. This class will hold methods that calculate a score for a fictitious game that requires the player to hit targets in the quickest time possible. Versions of the calculation will be available for adults and children and we will use a delegate to determine which is used.
Add the following code to the Scoreboard class to create the two scoring mechanisms:
// 10 points per target, -2 point per second
public static int CalculateAdultScore(int seconds, int targets)
{
return (targets * 10) - (seconds * 2);
}
// 15 points per target, -1 point per second
public static int CalculateChildScore(int seconds, int targets)
{
return (targets * 15) - seconds;
}
Declaring the Delegate
We will assign which scoring calculation is used at run-time within the Main method of the program. To be able to change the scoring method at run-time, a delegate must be declared. The delegate can be declared either within the class, in which case it is available only to that class' members, in the namespace so that it is available to all contained classes or outside of the namespace to be globally visible. In this case, add the following code within the application's "Program" class.
delegate int CalculateScore(int seconds, int targets);
NB: In the sample the parameters have the same names as those of the methods that will be referenced by the delegate. This is not a requirement though the data types must match.
27 January 2008