This article discusses the basics of delegates in C# and how to take advantage of delegates by implementing them in your applications.
A delegate in C# is similar to a FUNCTION POINTER in C or C++. Delegate can be defined as an object, which contains the address of a method. Delegate is a reference type used to encapsulate a method with a specific signature and return type.
As written in MSDN
"A Delegate is a type that references a method. Once a delegate is assigned a method, it behaves exactly like that method. The Delegate method can be used like any other method with parameter and return value".
.Net implements the concept of function pointer using Delegates.
Unlike c or C++ function pointer, delegates are
- Type safe
- Object Oriented
- Secure
Delegates have following properties
- Delegates are similar to C++ function pointer but it is type safe in nature.
- Delegate allows method to pass as an argument.
- Delegate can be chained together.
- Multiple methods can be called on a single event.
Delegate is a type which safely encapsulates a method. The type of the delegate is defined by name of the delegate. A delegate does not care about class of the object that it references. Any object will do, only matter is that the method signature should be the same as of delegate.
Any instance of a given delegate can refer to any instance or static method on any object of any type. Only one condition is there that signature of method matches the signature of delegate.
Mainly Delegate is used by creating first and then making object of that.
Main Advantage Delegate is effective use of delegate increase performance of application.
Syntax of a delegate
Step 1: Declaration
Delegate is getting declared here.
Modifer delegate return_type delegate_name ( [Parameter....])
Step 2: Instantiation
Object of delegate is getting created as passing method as argument
Delegate_name delg_object_name = new Delegate_name( method_name);
Here method_name signature must be same as of signature of delegate.
Step 3: Invocation
Delegate is getting called here.
Delg_object_name([parameter....]);
Delegate Example 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelgateForNotes
{
class Program
{
// Declaring A delegate , which will refer function having two parameter and will return integer
public delegate int AddDelegate(int num1, int num2);
static void Main(string[] args)
{
// Creating method of delegate, and passing Function Add as argument.
AddDelegate funct1= new AddDelegate(Add);
// Invoking Delegate.....
int k=funct1(7,2);
Console.WriteLine(" Sumation = {0}",k);
Console.Read();
}
// Static Function Add, which having same signature as of delegate
public static int Add(int num1, int num2)
{
Console.WriteLine("I am called by Delegate");
int sumation;
sumation= num1+ num2;
return sumation;
}
}
}
Output:
I am called by Delegate
Sumation =9
Purpose of this above code is to calculate a sum of two numbers. Add is a static function to compute sum of two integers. Signature of Add function is same as of signature of delegate. Here delegate is AddDelegate.
On Breaking the above code in steps
Step 1:
Creating Delegate.
public delegate int AddDelegate(int num1, int num2);
here AddDelegate is name of delegate.
Return type of delegate is int.
Delegate is taking two integer as input parameter.
Access modifer of delegate is Public.
In above signature keyword "delegate" defines signature is of delegate signature.
So delegate AddDelegate can refer any method having two integer parameter and returning one integer value.
Step 2:
Making Object of delegate.
AddDelegate funct1= new AddDelegate(Add);
Funct1 is name of the object.
Note: In case of delegate , object of delegate is also called as delegate. So in this case funct1 can be called as delegate.
As constructor of delegate, here a Method (Add) is passed. Signature of Add method and AddDelegate delegate is exactly same.
Add is a static method.
Step 3:
Invoking delegate
int k=funct1(7,2);
funct1 is getting called . Here 7, 2 are passed as parameter.
Delegate Example 2
This is bubble sort example. Here three classes have been created.
- BubbleSortClass.cs
- Student.cs
- Program.cs
BubbleSortClass.cs
This class will hold a static function called Sort. The return type of this function is void. As an argument, it is taking an Array, which is to be sort and a method which is comparing two objects.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelgateForNotes
{
public class BubbleSortClass
{
static public void Sort(object[] sortArray,.CompareDelegate gtMethod)
{
for (int i = 0; i < sortArray.Length; i++)
{
for (int j = 0; j < sortArray.Length; j++)
{
if(gtMethod(sortArray[j],sortArray[i]))
{
object temp= sortArray[i];
sortArray[i] = sortArray[j];
sortArray[j]=temp;
}
}
}
}
}
}
Student.cs
The object of this class is going to be sort using the Bubble sort. In this class, the static function RhsIsGreater is performing the function of comparing two Student objects.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelgateForNotes
{
// Student class
class Student
{
private string name;
private int rollno;
private int marks;
// Constructor to initaliaze object
public Student(string name, int rollno, int marks)
{
this.name = name;
this.rollno = rollno;
this.marks = marks;
}
// Overriding string method to display Student details
public override string ToString()
{
return string.Format(" Name => {0}, RollNumber => {1} , Marks => {2} ", name, rollno, marks);
}
// user defind function which is comparing two object and returning bool value
public static bool RhsIsGreater(object lhs, object rhs)
{
Student stdLhs = (Student)lhs;
Student stdRhs = (Student)rhs;
return (stdRhs.marks > stdLhs.marks);
}
}
}
The RhsIsGreater function is taking two object as argument. Inside function, first typecasting has been done. Then boolean value is getting returned.
Program.cs
This is main program. Here delegate is getting created and sorted array is getting display.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelgateForNotes
{
public class Program
{
// Declaring A delegate , which will refer function having two object parameter and will return boolean value
public delegate bool CompareDelegate(object lhs, object rhs);
static void Main(string[] args)
{
// Creating array of Student objects.
Student[] students = {
new Student("Mark", 1, 799),
new Student ("David",2,545),
new Student (" Lavish",3,999),
new Student ("Voora",4,228),
new Student ("Boll",5,768),
new Student (" Donna",6,367),
new Student ("Adam",7,799),
new Student("Steve",8, 867),
new Student (" Ricky",9,978),
new Student (" Brett",10,567)
};
// Creating Delegate passing static method of Student class as argument
CompareDelegate StudentCompareOp = new CompareDelegate(Student.RhsIsGreater);
// Now calling static method of BubbleSortClass , passing Stuednt object arraay and delegate as argument
BubbleSortClass.Sort(students,StudentCompareOp);
for(int i=0; i< students.Length;i++)
{
Console.WriteLine(students[i].ToString());
}
Console.Read();
}
}
}
MultiCast Delegates
A delegate which wrap up more than one method is called Multicast Delegates. When a multicast delegate is get called, it will successively call each functions in order. Multicast Delegate allow to chain together several functions. These chain functions can be called together when delegate is invoked. Every Delegate type has a built in support for dealing with multiiple handlers. Delegate gets this support by inheriting from the MultiCastDelegate class.
To work with Multicast Delegate , delegate signature should return void. Otherwise only last method result can be fetched.
Operators used are
+= this operator is used to add functions in delegate .
-= this operatir is used to remove function from delegate.
Delegate classes
System.Delegate
The purpose of a single delegate instance is very similar to a method pointer from C++. However, in C# don't use method pointers, rather, it save the "metadata" that identifies the target method to call. System.Delegate contains two critical data elements. Firstly, it contains an instance of System.Reflection.MethodInfo – in other words, the .NET metadata that enables method invocation using reflection.
The second aspect of System.Delegate is the object instance on which the method needs to be invoked. Given an unlimited number of objects that could support a method that matches the MethodInfo signature, we also need to be able to identify which objects to notify. The only exception is when the method identified by MethodInfo is static – in which case the object reference stored by System.Delegate is null.
System.MulticastDelegate
System.MulticastDelegate therefore, adds to delegates the support for notifying multiple subscribers. This is enabled through System.MulticastDelegate's containment of another System.MulticastDelegate instance. On adding a subscriber to a multicast delegate, the MulticastDelegate class creates a new instance of the delegate type, stores the object reference and the method pointer for the added method into the new instance, and adds the new delegate instance as the next item in a list of delegate instances. In effect, the MulticastDelegate class maintains a linked list of delegate objects.
Sequential Invocation
When invoking the multicast delegate, each delegate instance in the linked list is called sequentially. This sequential invocation, however, leads to problems if the invoked method throws an exception or if the delegate itself returns data.
Multicast Delegate Example 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MulticastDelegate1
{
class Program
{
// Decelaring delegate here, which will refer to method having void return type and one string as argument
public delegate void showDelegate(string s);
static void Main(string[] args)
{
showDelegate s = Display;
s += Show;
s("Hello");
s("Scott");
Console.Read();
}
// User Defind static function to display
public static void Display(string title)
{
Console.WriteLine(title);
}
// User defind static function
public static void Show(string title)
{
Console.WriteLine(title);
}
}
}
OUTPUT:
Hello
Hello
Scott
Scott
In the above example, the showDelegate is a delegate, which can refer any method having return type void and one string as parameter. There are two static user defined functions called Display and Show.
Multicast Delegate Example 2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MulticastDelegate
{
// user defined class for math operation. This class contains two static method. one method for squre and another method for double the number.
class MathOperation
{
// Multiply by two method, this method multiply number by 2
public static void MultiplyByTwo(double d)
{
double res = d*2;
Console.WriteLine("Multiply: "+res.ToString());
}
// squre number method
public static void Squre(double e)
{
double res = e * e;
Console.WriteLine("Square"+res.ToString());
}
}
class NewProgram
{
// Decelaring delegate called del
public delegate void del(double Qr);
static void Main()
{
// Creating delegate
del d = MathOperation.MultiplyByTwo;
// adding method to del delegate using += operator
d += MathOperation.Squre;
// calling display function. passsing delegate and double value as parameter
Display(d, 2.00);
Display(d, 9.9);
Console.ReadLine();
}
// User defined function to display result and call appropirate operation
static void Display(del action, double value)
{
Console.WriteLine("Result = "+ value);
action(value);
}
}
The above code is implementing multicast delegate. In above code, there is a MathOperationClass, this class is containing two methods. One to double the input parameter and other to make squre of that.
public delegate void del(double Qr);
This is delegate decelaration. It will refer method having one double parameter and will return void.
Display function is taking delegate and double as parameter. This function is displaying the result and calling the delegate.