Delegates Basics
Delegates are references to methods. So far we have used references to objects, e.g. Stack st = new Stack();
Here st is a reference to an object of the Stack class type. Hence, each reference has two properties: 1. The type of object (class) the reference can point to. 2. The actual object referenced (or pointed to) by the reference.
Delegates are similar to object references, but are used to reference methods instead of objects. The type of a delegate is the type or signature of the method rather than the class. Hence a delegate has three properties:
Delegates are references to methods. So far we have used references to objects, e.g. Stack st = new Stack();
Here st is a reference to an object of the Stack class type. Hence, each reference has two properties: 1. The type of object (class) the reference can point to. 2. The actual object referenced (or pointed to) by the reference.
Delegates are similar to object references, but are used to reference methods instead of objects. The type of a delegate is the type or signature of the method rather than the class. Hence a delegate has three properties:
1. The type or signature of the method that the delegate can point to
2. The delegate reference which can be used to reference a method
3. The actual method referenced by the delegate
Author's Note: The concept of delegates is similar to the function pointers used in C++.
Author's Note: The concept of delegates is similar to the function pointers used in C++.
1.The type or signature of the method the delegate can point to
Before using a delegate, we need to specify the type or signature of the method the delegate can reference. The signature of a method includes its return type and the type of parameters which it requires to be passed. For example:
Before using a delegate, we need to specify the type or signature of the method the delegate can reference. The signature of a method includes its return type and the type of parameters which it requires to be passed. For example:
int someMethod(string [] args)
Is the common signature of the Main() method of a C# programs defined as:
int Main(string [] args)
{
...
}
And for the following Add() method:
int Add(int a, int b)
{
return a+b;
}
The signature will be:
int aMethod(int p, int q)
Which is also the signature of following Subtract() method:
int Subtract(int c, int d)
{
return c-d;
}
It should be noticed from the above examples that the name of a method is not the part of its signature; the signature only involves its return type and parameters.
In case of delegates, we define the type of a delegate using the delegate keyword, e.g.
delegate int MyDelegate(int p, int q);
Here we have defined a delegate type with the name 'MyDelegate'. The
reference of this delegate type can be used to point to any method which takes
two integers as parameters and returns an integer value.
2.The delegate reference, that can be used to reference a method
Once we have defined a delegate type, we can set it to reference actual methods with matching signatures. A delegate reference can be declared just like an object reference. For example, a reference of type MyDelegate (defined above) can be declared as:
2.The delegate reference, that can be used to reference a method
Once we have defined a delegate type, we can set it to reference actual methods with matching signatures. A delegate reference can be declared just like an object reference. For example, a reference of type MyDelegate (defined above) can be declared as:
MyDelegate arithMethod;
The delegate reference arithMethod can now reference any method whose
signature is identical to the signature of MyDelegate.
3.The actual method referenced by the delegate
The delegate reference can be made to reference any method with a matching signature by passing its name as the parameter of delegate:
3.The actual method referenced by the delegate
The delegate reference can be made to reference any method with a matching signature by passing its name as the parameter of delegate:
arithMethod = new MyDelegate(Add);
Here, the arithMethod delegate reference is made to point to the Add()
method by passing its name as a parameter to the delegate type (MyDelegate).
The last two steps can be merged together in a single statement, like this:-
The last two steps can be merged together in a single statement, like this:-
MyDelegate arithMethod = new MyDelegate(Add);
Calling the actual method through its delegate
Once the delegate reference 'arithMethod' has been made to point to the Add() method, it can be used to call the actual method like this:-
Once the delegate reference 'arithMethod' has been made to point to the Add() method, it can be used to call the actual method like this:-
int r = arithMethod(3, 4);
The complete source code of the program is presented below.
using System;
namespace CSharpSchool
{
class Test
{
delegate int MyDelegate(int p, int q);
static void Main()
{
MyDelegate arithMethod = new MyDelegate(Add);
int r = arithMethod(3, 4);
Console.WriteLine("The result of arthmetic operation
`+' on 3 and 4 is: {0}",r);
}
static int Add(int a, int b)
{
return a + b;
}
}
}
The result of the above program will be
The result of arthmetic operation `+' on 3 and 4 is: 7
Press any key to continue
The above program can be changed so that the arithmetic operation can be selected by the user.
The result of arthmetic operation `+' on 3 and 4 is: 7
Press any key to continue
The above program can be changed so that the arithmetic operation can be selected by the user.
using System;
namespace CSharpSchool
{
class Test
{
delegate int MyDelegate(int p, int q);
static void Main()
{
MyDelegate arithMethod = null;
Console.WriteLine("Which arithmetic operation you
like to perform on 3 and 4?");
Console.WriteLine("Press + for Add ");
Console.WriteLine("Press - for Subtract ");
Console.Write("Press m for Maximum Number ");
char choice = (char) Console.Read();
switch(choice)
{
case '+':
arithMethod = new MyDelegate(Add);
break;
case '-':
arithMethod = new MyDelegate(Subtract);
break;
case 'm':
arithMethod = new MyDelegate(Max);
break;
}
int r = arithMethod(3, 4);
Console.WriteLine("\nThe result of arithmetic
operation {0} on 3 and 4 is: {1}", choice, r);
}
static int Add(int a, int b)
{
return a + b;
}
static int Subtract(int a, int b)
{
return a-b;
}
static int Max(int c, int d)
{
if(c>d)
return c;
else
return d;
}
}
}
Here we have
defined three methods with the same signature; Add(), Subtract() and Max(). A
delegate type called MyDelegate is defined so that its reference arithDelegate
can point to any method with a matching signature. The delegate reference
'arithDelegate' is used to point out the particular method based on the user
input at runtime. The sample output of the code is:
Which arithmetic operation you like to perform on 3 and 4?
Press + for Add
Press - for Subtract
Press m for Maximum Number -
The result of arithmetic operation - on 3 and 4 is: -1
Press any key to continue
Since, in the output above, the user pressed '-', the delegate reference is made to reference and call the Subtract() method. The above program shows that the same delegate reference can be used to point to various methods as long as their signature is same as the signature specified by the delegate type.
Confusion in terminology
Unfortunately, the same term 'delegate' is used for both 'delegate type' and 'delegate reference', which sometimes creates confusion in the reader's mind. For the sake of clarity, we are continuously using the term 'delegate type' and 'delegate reference' and will recommend the readers to also use these.
Which arithmetic operation you like to perform on 3 and 4?
Press + for Add
Press - for Subtract
Press m for Maximum Number -
The result of arithmetic operation - on 3 and 4 is: -1
Press any key to continue
Since, in the output above, the user pressed '-', the delegate reference is made to reference and call the Subtract() method. The above program shows that the same delegate reference can be used to point to various methods as long as their signature is same as the signature specified by the delegate type.
Confusion in terminology
Unfortunately, the same term 'delegate' is used for both 'delegate type' and 'delegate reference', which sometimes creates confusion in the reader's mind. For the sake of clarity, we are continuously using the term 'delegate type' and 'delegate reference' and will recommend the readers to also use these.
Delegates in the .Net Framework
Although C# presents delegates as a keyword and as a first class language construct, in .Net delegates are present as a reference type, and all delegates inherit from the System.Delegate type. Hence, technically, our prior definition that said 'a delegate is a reference to a method' is not quite appropriate. A delegate is a reference type derived from System.Delegate and its instances can be used to call methods with matching signatures. Another important thing to note here is that since defining a delegate means creating a new sub-type of System.Delegate, the delegates can not be defined within a method (which is also true for ordinary types). This is the reason why we have defined the delegate MyDelegate outside the Main() method in the example code of this lesson.
Although C# presents delegates as a keyword and as a first class language construct, in .Net delegates are present as a reference type, and all delegates inherit from the System.Delegate type. Hence, technically, our prior definition that said 'a delegate is a reference to a method' is not quite appropriate. A delegate is a reference type derived from System.Delegate and its instances can be used to call methods with matching signatures. Another important thing to note here is that since defining a delegate means creating a new sub-type of System.Delegate, the delegates can not be defined within a method (which is also true for ordinary types). This is the reason why we have defined the delegate MyDelegate outside the Main() method in the example code of this lesson.
class Test
{
delegate int MyDelegate(int p, int q);
static void Main()
{
MyDelegate arithMethod = null;
...
}
}
Passing delegates to methods
Just like a reference to an object can be passed to other objects, the delegate reference of one method can be passed to another method. For example, lets make a method called 'PerformArithOperation()', which takes two integers and a delegate reference of type MyDelegate, and calls the encapsulated method using the two integers.
static void PerformArithOperation(int a, int b, MyDelegate arithOperation)
{
int r = arithOperation(a, b);
Console.WriteLine("\nThe result of arithmetic operation on 3
and 4 is: {0}", r);
}
Now in the Main() method, we will call this method as
PerformArithOperation(3, 4, arithMethod);
Hence, the task of collecting and printing the result has been delegated (or transferred) to the PerformArithOperation() method. The complete source code of the program is shown below.
using System;
namespace CSharpSchool
{
class Test
{
delegate int MyDelegate(int p, int q);
static void Main()
{
MyDelegate arithMethod = null;
Console.WriteLine("Which arithmetic operation you
like to perform on 3 and 4?");
Console.WriteLine("Press + for Add ");
Console.WriteLine("Press - for Subtract ");
Console.Write("Press m for Maximum Number ");
char choice = (char) Console.Read();
switch(choice)
{
case '+':
arithMethod = new MyDelegate(Add);
break;
case '-':
arithMethod = new MyDelegate(Subtract);
break;
case 'm':
arithMethod = new MyDelegate(Max);
break;
}
PerformArithOperation(3, 4, arithMethod);
}
static void PerformArithOperation(int a, int b, MyDelegate
arithOperation)
{
int r = arithOperation(a, b);
Console.WriteLine("\nThe result of arithmetic
operation on 3 and 4 is: {0}", r);
}
static int Add(int a, int b)
{
return a + b;
}
static int Subtract(int a, int b)
{
return a-b;
}
static int Max(int c, int d)
{
if(c>d)
return c;
else
return d;
}
}
}
Multicast Delegates
A special feature of delegates is that a single delegate can encapsulate more than one method of a matching signature. These kind of delegates are called 'Multicast Delegates'. Internally, multicast delegates are sub-types of System.MulticastDelegate, which itself is a subclass of System.Delegate. The most important point to remember about multicast delegates is that "The return type of a multicast delegate type must be void". The reason for this limitation is that a multicast delegate may have multiple methods in its invocation list. Since a single delegate (or method) invocation can return only a single value, a multicast delegate type must have the void return type.
Implementing a Multicast Delegate
A multicast delegate is defined in exactly the same way as a simple delegates, with the exception that the return type of a multicast delegate is strictly void.
delegate void MyMulticastDelegate(int p, int q);
The different methods are added to multicast delegate's invocation list by using '+=' assignment operator, like this:
MyMulticastDelegate arithMethod = null;
arithMethod = new MyMulticastDelegate(Add);
arithMethod += new MyMulticastDelegate(Subtract);
arithMethod += new MyMulticastDelegate(Max);
The invocation of a multicast delegate is again similar to that of normal delegates and methods except that it in turn calls all the encapsulated methods.
arithMethod(3, 4);
The complete source code of this example is shown below.
using System;
namespace CSharpSchool
{
class Test
{
delegate void MyMulticastDelegate(int p, int q);
static void Main()
{
MyMulticastDelegate arithMethod = null;
arithMethod = new MyDelegate(Add);
arithMethod += new MyDelegate(Subtract);
arithMethod += new MyDelegate(Max);
arithMethod(3, 4);
}
static void Add(int a, int b)
{
Console.WriteLine("The sum of 3 and 4 is: {0}", a+b);
}
static void Subtract(int a, int b)
{
Console.WriteLine("The difference of 3 and 4 is: {0}", a-b);
}
static void Max(int c, int d)
{
if(c>d)
Console.WriteLine("The Maximum of 3 and 4 is: {0}", c);
else
Console.WriteLine("The Maximum of 3 and 4 is: {0}", d);
}
}
}
Note that we have changed the Add(), Subtract() and Max() methods so that they have a void return type and print out the result of their respective operations within the body of the method. The output of the program is:
The sum of 3 and 4 is: 7
The difference of 3 and 4 is: -1
The Maximum of 3 and 4 is: 4
Press any key to continue
Note that the single delegate invocation has invoked all of the encapsulated methods. This concept is used in the event handling mechanism of .Net, described later in the lesson, where each event handler method is called (when the event is fired) through the multicast delegate.
Previous Page Next Page
Removing a method from the multicast delegate's invocation list
Just as we can add methods to the multicast delegate's invocation list using '+=' operator, we can remove a method from the multicast delegate's invocation list using the '-=' operator. Consider the revised Main() method of the previous program shown below.
static void Main()
{
Console.WriteLine("Adding 3 methods to the multicast delegate...");
Console.WriteLine("=============================================");
MyMulticastDelegate arithMethod = null;
arithMethod = new MyMulticastDelegate(Add);
arithMethod += new MyMulticastDelegate(Subtract);
arithMethod += new MyMulticastDelegate(Max);
arithMethod(3, 4);
Console.WriteLine("\nRemoving Subtract() method from the multicast
delegate...");
Console.WriteLine ("=========================================================");
arithMethod -= new MyMulticastDelegate(Subtract);
arithMethod(3, 4);
}
First we have added the three methods (Add(), Subtract() and Max()) to the multicast delegate 'MyMulticastDelegate' and invoked the delegate. Later, we removed the Subtract() method from the multicast delegate and invoked it again. The output of the code will be:
Adding 3 methods to the multicast delegate...
=============================================
The sum of 3 and 4 is: 7
The difference of 3 and 4 is: -1
The Maximum of 3 and 4 is: 4
Removing Subtract() method from the multicast delegate...
=========================================================
The sum of 3 and 4 is: 7
The Maximum of 3 and 4 is: 4
Press any key to continue
The output shows that the Subtract() method has been removed from the delegate's invocation list and is not called when the delegate is invoked the second time.
No comments:
Post a Comment