In this article, we will understand about Delegates in C#, before we begin I would like to tell you, if you have learned to code in C or C++ language then you must be aware of pointers to functions in these languages, similar kind of work is done by Delegates in C#. It's a new type of object in C#.

Understanding delegates in C#

First, we will understand it in basic language, basically, a Delegate is a type in C#. In delegate, it contains the reference to several methods and call them when needed. So, you create numbers of methods as you need and attach it to delegates. At runtime, an event gets fired and delegates dynamically call the function and show the result.

Simple Example

using System;
					
    public class DelegateTest
    {
        
        //Creating Delegates with no parameters and no return type.
        public delegate void FirstDelegate();
 
        public void funtion1()
        {
            Console.WriteLine("I am Function 1");
        }
        public void funtion2()
        {
            Console.WriteLine("I am Function 2");
        }
        
    }
 
    public class Program
    {
       public static void Main(string[] args)
        {
            DelegateTest testdelegate = new DelegateTest();
            //Instantiation
            DelegateTest.FirstDelegate fd1 = new DelegateTest.FirstDelegate(testdelegate.funtion1);
            DelegateTest.FirstDelegate fd2 = new DelegateTest.FirstDelegate(testdelegate.funtion2);            
 
          //Invocation 
            fd1();
            fd2();
                     
        }
    }

Output:

I am Function 1
I am Function 2

In the above example, we created a class "DelegateTest" and declared a delegate inside it, with two methods.

In the main function, we create an object of delegates. You must remember that a delegate always requires a function while initialized and finally delegate is called.

delegates-in-csharp-with-example-min.png

Here are the few important points of Delegates:

  • A delegate is like a pointer to a function.
  • It is a reference type data type and it holds the reference of a method.
  • The reference can be changed at runtime.
  • All the delegates are implicitly derived from System.Delegate class.
  • You can take advantage of delegates in C# to implement events and call back methods. A multicast delegate is one that can point to one or more methods that have identical signatures.

Delegate can be declared using delegate keyword.

Syntax to declare delegate

delegate double DoubleOp(double x);

In the above declaration, DoubleOp is a function which takes double as a argument and also returns double, which is used to perform mathematical operations, it can be used to call Math Operations using Delegates.

So, basically looking at the above example syntax for the delegate would be

delegate <return type> <delegate-name> <parameter list>

More complex example, of Delegate:

using System;

public class MathOPs
{
    public static double Multiply(double value)
    {
        return value * 2;
    }

    public static double Square(double value)
    {

        return value * value;

    }

}


delegate double DoubleOp(double x);
 

class Application
{
    static void Main()
    {
        DoubleOp[] operations =
            {
               MathOPs.Multiply,
               MathOPs.Square
            };

        for (int i = 0; i < operations.Length; i++)
        {
            Console.WriteLine("Operation[{0}]:", i);
            ProcessAndDisplayNumber(operations[i], 5.0);
            ProcessAndDisplayNumber(operations[i], 13.55);
            ProcessAndDisplayNumber(operations[i], 1.732);
            Console.WriteLine();
        }
        Console.ReadLine();
    }
 
    static void ProcessAndDisplayNumber(DoubleOp action, double value)
    {

        double result = action(value);

        Console.WriteLine(

           "Value : {0}  Result : {1}", value, result);

    }

}

Output of the above code will be

Operation[0]:
Value : 5  Result : 10
Value : 13.55  Result : 27.1
Value : 1.732  Result : 3.464

Operation[1]:
Value : 5  Result : 25
Value : 13.55  Result : 183.6025
Value : 1.732  Result : 2.999824

Multicast delegate:

The delegate can points to multiple methods. Multicast delegate is a delegate which holds a reference to more than one method. The "+" operator adds a function to the delegate object and the "-" operator removes an existing function from a delegate object.

Here is an example of multicast delegate

using System;

delegate void ArDelegate(int a, int b);

public class ArithematicOperation {
	 public static void Add(int a, int b) {
	  Console.WriteLine("{0} + {1} = {2}", a, b, a + b);
	 }
	 public static void Sub(int a, int b) {
	  Console.WriteLine("{0} - {1} = {2}", a, b, a - b);
	 }
}

public class DelegateProgram {

	 public static void Main() {
		  ArDelegate del = new ArDelegate(ArithematicOperation.Add);
		  //multicast delegate here
		  del += new ArDelegate(ArithematicOperation.Sub);
		  del(4, 2);

		  del -= new ArDelegate(ArithematicOperation.Sub);
		  del(1, 9);
		  
	 }

}

Output of the above code will be

4 + 2 = 6
4 - 2 = 2
1 + 9 = 10

Advantages of using Delegates in C#:

  • Can lead to easy reuse of code
  • Can provide a great amount of flexibility in your designs
  • Allow you to develop libraries and classes that are easily extensible, since it provides an easy way to hook in other functionality (for example, a where clause in LINQ can use a delegate [Func<T,bool>] to filter on, without having to write new code in the Where method

Where or When to use delegates?

Suppose you want to write a procedure to integrate some real-valued function f (x) over some interval [a, b]. Say we want to use the 3-Point Gaussian method to do this 

// 'f' is the integrand we want to integrate over [a, b] with 'n' subintervals.
static double Gauss3(Integrand f, double a, double b, int n) {
  double res = 0;

  // some code here
  // ...

  return res;
}

So we can pass in any,Integrand f, and get its definite integral over the closed interval.Just what type should Integrand be?

Without Delegates

Well, without delegates, we'd need some sort of interface with a single method, say eval declared as follows:

// Interface describing real-valued functions of one variable.
interface Integrand {
  double eval(double x);
}

Then we'd need to create a whole bunch of classes implementing this interface, as follows:

// Some function
class MyFunc1 : Integrand {
  public double eval(double x) {
    return /* some_result */ ;
  }
}

// Some other function
class MyFunc2 : Integrand {
  public double eval(double x) {
    return /* some_result */ ;
  }
}

Then to use them in our Gauss3 method, we need to invoke it as follows:

double res1 = Gauss3(new MyFunc1(), -1, 1, 16);
double res2 = Gauss3(new MyFunc2(), 0, Math.PI, 16);

And Gauss3 needs to do the look like the following:

static double Gauss3(Integrand f, double a, double b, int n) {
  // Use the integrand passed in:
  f.eval(x);
}

So we need to do all that just to use our arbitrary functions in Guass3.

With Delegates

Declare your delegate first

public delegate double Integrand(double x);

Now we can define some static (or not) functions adhering to that prototype:

class Program {
   public delegate double Integrand(double x);   
   // Define implementations to above delegate 
   // with similar input and output types
   static double MyFunc1(double x) { /* ... */ }
   static double MyFunc2(double x) { /* ... */ }
   // ... etc ...

   public static double Gauss3(Integrand f, ...) { 
      // Now just call the function naturally, no f.eval() stuff.
      double a = f(x); 
      // ...
   }

   // Let's use it
   static void Main() {
     // Just pass the function in naturally (well, its reference).
     double res = Gauss3(MyFunc1, a, b, n);
     double res = Gauss3(MyFunc2, a, b, n);    
   }
}
//example source
// https://stackoverflow.com/a/2020501

Now, looking at the above example you can see, we didn't create any interface, no .eval stuff, no object instantiation, just simple function-pointer like usage, for a simple task.