Learning the Basics of Delegates in C#


Delegates make it possible to programmatically change method calls, and plug new codes in to existing classes. For these you need to know what are the method matches delegate's signature and its return type. Delegates are similar to C++ function pointers but delegates type safe and Object Oriented. Methods don't need to match the delegate signature exactly.

What is Covariance and Contravariance in Delegates ?


Covariance and Contravariance provides kind of flexibility when matching the method signature with delegate type that is defined.

Covariance permits a method to have a more derived return type than what is defined when the delegate define. Contravariance permits a method to have less derived parameter types than in the delegate type.

A delegate is a type; it encapsulates a method, see the below example:

// Define the Delegate
public delegate void TestDelegate(string Message);

// Creating a method with string argument
public static void DisplayMessage(string Message)
{
    Console.WriteLine(Message);
    Console.ReadKey(); 

static void Main(string[] args)
{
    // Instantiate the delegate and encapsulates the method "DisplayMessage"
    TestDelegate Test = DisplayMessage;

    // call the delegate
    Test("This is my delegate method");
}


This is a very simple example but delegates can be used in advance ways rather than this. The instantiated delegate is an object, it can be passed as parameter, or assign to a property. When a delegate is used in this way, the code used by the delegate does not need any knowledge of the method being used. This is similar functionality provide by interface encapsulation.

What is Multicasting?

In a delegate you can have more than one method to invoke, you can assign a method to a delegate using "=" and you can add method a to a delegate where it has assigned a method to invoke by using "+" if you want you can remove an assigned method from a delegate where it has more methods to invoke by using "-". This is called multicasting.

Multicasting example:

namespace Delegates_Test2
{
    delegate void Del(); 
    class
Simple
    {
        public void MethodA()
        {
            System.Console.WriteLine("Message from the method A.");
        } 
        static public void MethodB()
        {
            System.Console.WriteLine("Message from the method B.");
        } 
    }
}
 
namespace Delegates_Test2
{
    class
Program
    {
        static void Main(string[] args)
        {
            Simple sc = new Simple();
 
           
// Map delegate to the method: A
            Del d = sc.MethodA;         
 
           
// Map method: B with multicasting
            d += Simple.MethodB;
           
            d();
// Both methods are excute here 
            Console.ReadKey(); 
        }
    }
}


Generic Delegates

The delegate can define its own generic type parameters.

How to define:

public delegate void MyDelegate<T>(T item);

Generic delegate example:

namespace Generic_Delegate
{
   
//Generic Delegate define here with return value of T, and both T arguments
    public delegate T Calculator<T> (T arg1, T arg2);
 
    class
MathUtility
    {
       
// Generic method to execute with Two generic argument values and one generic  methods  
        public static void Calculate<T>(T[] values1, T[] values2, Calculator<T> t)
        {
            for (int i=0; i < values1.Length; i++)
            {
                values1[i] = t(values1[i],values2[i]);
// execute the T method with two of T arguments
                //And assigning results to First parameter      
            }
        }
    }

 
namespace Generic_Delegate
{
    class
Program
    {
       
// My method to find  square value
        static int FindSquareValue(int x, int y)
        {
           
// Your method's implementation
            return (x * y); // Your method have defined to return the results
        }
 
        
// My Method to find dividence with first value by second value
        static double FindDividence(double a, double b)
        {
           
// Your method's implementation
            return (a / b);  // Your method have defined to return the results
        }
          
        static void Main(string[] args)
        {
           
// To get Square
            int[] height = { 10, 5, 8 };
            int[] width = { 4, 3, 6 };
 
            MathUtility.Calculate(height, width, FindSquareValue);
// Dynamically hook with FindSquare method

            // You're only passing the both values and method          
 
            Console.WriteLine("Display Square Values..."); 
           
            foreach (int i in height)
            {
                Console.WriteLine(i.ToString());   
            }
 
          
// To get Dividence
            double[] Val1 = { 10, 80, 60 };
            double[] val2 = {8,3,4};
 
            MathUtility.Calculate(Val1, val2, FindDividence);
 
            Console.WriteLine("Display Dividence values..."); 
 
            foreach (double d in Val1)
            {
                Console.WriteLine(d.ToString());  
            } 
            Console.ReadKey(); 
        }
    }
}

Next Recommended Readings