Introduction
A delegate is an object that can refer to a method. Thus, when you create a delegate, you are creating an object that can hold a reference to a method. Furthermore, the method can be called through this reference. Thus, a delegate can invoke the method to which it refers (It's Like a function pointer in c/c++).
Paragraph Heading 1
Even though a method is not an object, it still has a physical location in memory. This address is the entry point of the method and is the address called when the method is invoked. The address of a method can be assigned to a delegate. Once a delegate refers to a method, the method can be called through that delegate. Furthermore, the same delegate can be used to call a different method by simply changing the method to which the delegate refers. The principal advantage of a delegate is that it allows you to specify a call to a method, but the method actually invoked is determined at runtime, not at compile time.
A delegate is declared using the keyword delegate. The general form of a delegate declaration is shown here:
delegate ret-type name(parameter-list);
Here, ret-type is the type of value returned by the methods that the delegate will be calling. The name of the delegate is specified by name. The parameters required by the methods called through the delegate are specified in the parameter-list. Once declared, a delegate can call only methods whose return type and parameter list match those specified by the delegate.
As mentioned, the key point about delegates is that a delegate can be used to call any method that agrees with its signature. This makes it possible to determine which method to invoke at runtime. Furthermore, the method invoked can be an instance method associated with an object, or a static method associated with a class. All that matters is that the signature of the method agrees with that of the delegate.
To see delegates in action, let's begin with the simple example shown here:
[]CODE]
// A simple delegate example.
using System;
// Declare a delegate.
delegate string strMod(string str);
class DelegateTest
{
// Replaces spaces with hyphens.
static string replaceSpaces(string a)
{
Console.WriteLine("Replaces spaces with hyphens.");
return a.Replace(' ', '-');
}
// Remove spaces.
static string removeSpaces(string a)
{
string temp = "";
int i;
Console.WriteLine("Removing spaces.");
for(i=0; i < a.Length; i++)
if(a[i] != ' ') temp += a[i];
return temp;
}
// Reverse a string.
static string reverse(string a)
{
string temp = "";
int i, j;
Console.WriteLine("Reversing string.");
for(j=0, i=a.Length-1; i >= 0; i--, j++)
temp += a[i];
return temp;
}
public static void Main()
{
// Construct delegates.
strMod strOp = new strMod(replaceSpaces);
string str;
// Call methods through delegates.
str = strOp("This is a test.");
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();
strOp = new strMod(removeSpaces);
str = strOp("This is a test.");
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();
strOp = new strMod(reverse);
str = strOp("This is a test.");
Console.WriteLine("Resulting string: " + str);
}
[]/CODE]}
Multicasting
One of the most exciting features of a delegate is its support for multicasting. In simple terms, multicasting is the ability to create a chain of methods that will be automatically called when a delegate is invoked. Such a chain is very easy to create. Simply instantiate a delegate, and then use the += operator to add methods to the chain. To remove a method, use – =. (You can also use the +, –, and = operators separately to add and subtract delegates, but += and – = are more convenient.) The only restriction is that the delegate being multicast must have a void return type.
Example
[]CODE]
// Demonstrate multicasting.
using System;
// Declare a delegate.
delegate void strMod(ref string str);
class StringOps
{
// Replaces spaces with hyphens.
static void replaceSpaces(ref string a)
{
Console.WriteLine("Replaces spaces with hyphens.");
a = a.Replace(' ', '-');
}
// Remove spaces.
static void removeSpaces(ref string a)
{
string temp = "";
int i;
Console.WriteLine("Removing spaces.");
for(i=0; i < a.Length; i++)
if(a[i] != ' ') temp += a[i];
a = temp;
}
// Reverse a string.
static void reverse(ref string a)
{
string temp = "";
int i, j;
Console.WriteLine("Reversing string.");
for(j=0, i=a.Length-1; i >= 0; i--, j++)
temp += a[i];
a = temp;
}
public static void Main()
{
// Construct delegates.
strMod strOp;
strMod replaceSp = new strMod(replaceSpaces);
strMod removeSp = new strMod(removeSpaces);
strMod reverseStr = new strMod(reverse);
string str = "This is a test";
// set up multicast
strOp = replaceSp;
strOp += reverseStr;
// Call multicast
strOp(ref str);
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();
// remove replace and add remove
strOp -= replaceSp;
strOp += removeSp;
str = "This is a test."; // reset string
// Call multicast
strOp(ref str);
Console.WriteLine("Resulting string: " + str);
Console.WriteLine();
}
}
In general, delegates are useful for two main reasons.
First, delegates support events. Second, delegates give your program a way to execute a method at runtime without having to know precisely what that method is at compile time. This ability is quite useful when you want to create a framework that allows components to be plugged in. For example, imagine a drawing program (a bit like the standard Windows Paint accessory). Using a delegate, you could allow the user to plug in special color filters or image analyzers. Furthermore, the user could create a sequence of these filters or analyzers. Such a scheme would be easily handled using a delegate.