It is not compulsory to create delegates. It is just the easiest way in some situations to get the thing done.
If you have multiple methods with same signature (return type & number of parameters) and want to call all the methods with single object then using delegates is the best option.
C# delegates are similar to C++ function pointers and are type safe. A delegate is a reference type variable that holds the reference to a method. The reference can be changed at runtime.
All delegates are implicitly derived from the System.Delegate class. Delegates are especially used for implementing events and the call-back methods (Anonymous). Delegates allow methods to be passed as parameters. Delegate types are sealed and immutable type. Effective use of delegate improves the performance of application.
There are three types of delegates that can be used in C#.
- Single Delegate
- Multicast Delegate
- Generic Delegate
Declaring Delegates
Whenever we want to create delegate methods we need to declare with delegate keyword. Delegate methods signature should match exactly with the methods signature (Parameter list) that Invokes.
For example, consider a delegate:
public delegate int MyDelegate (string s);
The preceding delegate can be used to reference any method that has a single string parameter and returns an int type variable.
Syntax for delegate declaration is:
delegate <return type> <delegate-name> <parameter list>
Singlecast Delegate
Once a delegate type is declared, a delegate object must be created with the new keyword and be associated with a particular method. When creating a delegate, the argument passed to the new expression is written similar to a method call, but without the arguments to the method.
Following example demonstrates declaration, instantiation, and use of a delegate that can be used to reference methods that take an integer parameter and returns an integer value.
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
//create delegate instances
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
//calling the methods using the delegate objects
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following result:
Value of Num: 35
Value of Num: 175
Multicast Delegate
It is a delegate which holds the reference of more than one method. Delegates can be chained together; for example, multiple methods can be called on a single event
Delegate objects can be composed using the "+" operator. A composed delegate calls the two delegates it was composed from. Only delegates of the same type can be composed. The "-" operator can be used to remove a component delegate from a composed delegate.
Using this property of delegates you can create an invocation list of methods that will be called when a delegate is invoked. This is called multicasting of a delegate. The following program demonstrates multicasting of a delegate:
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl
{
class TestDelegate
{
static int num = 10;
public static int AddNum(int p)
{
num += p;
return num;
}
public static int MultNum(int q)
{
num *= q;
return num;
}
public static int getNum()
{
return num;
}
static void Main(string[] args)
{
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
nc(5);//calling multicast
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following result:
Value of Num: 75
Using Delegates
The following example demonstrates the use of delegate. The delegate printString can be used to reference method that takes a string as input and returns nothing.
We use this delegate to call two methods, the first prints the string to the console, and the second one prints it to a file:
using System;
using System.IO;
namespace DelegateAppl
{
class PrintString
{
static FileStream fs;
static StreamWriter sw;
public delegate void printString(string s);
public static void WriteToScreen(string str)
{
Console.WriteLine("The String is: {0}", str);
}
public static void WriteToFile(string s)
{
fs = new FileStream("c:\\msg.txt",FileMode.Append, FileAccess.Write);
sw = new StreamWriter(fs);
sw.WriteLine(s);
sw.Flush();
sw.Close();
fs.Close();
}
static void Main(string[] args)
{
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
ps1("Hello World");
ps2("Hello World");
Console.ReadKey();
}
}
}
When the above code is compiled and executed, it produces the following result:
The String is: Hello World
Generic Delegate
Generic Delegate was introduced in .NET 3.5 that don't require to define the delegate instance in order to invoke the methods.
There are three types of generic delegates:
Func
The Func
delegate defines a method that can be called on arguments and returns a result.
Action
The Action
delegate defines a method that can be called on arguments that returns void. In the given code example, delegate Action<string>
is defined with string
as argument.
Action<string> MyAction = y => Console.Write(y);
MyAction("Hello");
Console.ReadKey();
Predicate
The Predicate delegate defines a method that can be called on arguments and always returns Boolean type result.