Delegates in .NET

A delegate is a reference type and a type-safe function pointer that references methods using their memory addresses and invokes them dynamically at the run time of the program. A delegate has a specified set of parameters and a return type as a method and it invokes a method that has the matching parameters and a return type. It means that the parameters and the return type of a delegate must be the same as the parameters and the return type of a method it references to.

An instance of a delegate takes a method as a parameter and references it using its memory address. To invoke a method using a delegate, first, we define a custom delegate reference type using the delegate keyword and declare its parameters list and a return type depending on the target method then we declare an instance from it and instantiate it by assigning the target method to it as a parameter. When a method is assigned as a parameter to an instance of the delegate reference type, it stores the memory address of that method and invokes it dynamically during the runtime of the program.

An instance of the delegate invokes either a static method associated with a class or an instance method associated with an object. A delegate reference type is similar to other reference types but the main difference is that other reference types hold the references or the memory addresses of variables and a delegate reference type holds the reference or the memory address of a method like a function pointer in the C++ programming language.

A delegate is similar to function pointers in the C++ programming language. Function pointers of the C++ programming language are a pointer variable that points to a function using its memory address. To invoke a function using a function pointer, we simply assign the memory address of the method to the function pointer variable and invoke it using its memory address. A function pointer variable in C++ is a pointer variable but its declaration is similar to the function declaration that has the matching parameters list and a return type with the parameters list and the return type of the function that points to it. Therefore, a function pointer variable in C++ programming invokes a function that has the matching parameters a return type.

The main difference between the C++ function pointers and the delegates is that the C++ function pointer holds only the memory address of a function and it does not carry any additional information such as the number of parameters used by the function, the types of the parameters, and the return type of the function while a delegate holds the memory address of a method and carries all the information associated with the method we want to invoke and also can access any variable visible to the enclosing scope.

The delegates are actually the .NET implementation of function pointers and they are object-oriented, type-safe, and secure, unlike C++ function pointers. Therefore, we can say that delegates are the .NET reference objects that can be used to invoke methods of matching signatures and return types. A delegate invokes a method synchronously and asynchronously and it can also be used to define callback methods. A callback method is a user-defined method that is used to process the result of an asynchronous operation in a separate thread.

Invoke Methods using Delegates

To invoke a method using a delegate we must use the following three steps.

  1. Declare a Delegate Type
  2. Instantiate a Delegate Instance
  3. Invoke the Method

The Declaration of Delegate Type

The declaration of the delegate defines a custom delegate reference type using the keyword delegate. A delegate reference type has a specified set of parameters and a return type depending on the method it references. A delegate reference type can be declared within the scope of a namespace or within the scope of a class. We cannot declare a delegate as a data member of a class and we cannot declare it as a local variable within the scope of a method because the declaration of a delegate is actually a new type definition and types can be defined only within the scope of a namespace and within the scope of a class. We cannot define any type within the scope of a method. The following is the general syntax to define a delegate reference type.

C# Syntax

[Modifiers] delegate ReturnType DelegateName([ParameterList]);

The declaration of a delegate type usually has five parts, such as modifiers, the delegate keyword, the return type, the delegate name, and a list of parameters. The first part of a delegate declaration is [Modifiers] which indicates an access modifier. The access modifiers are keywords used to specify the declared accessibility of a member or a data type. The main and important access modifiers are public, protected, private, and internal modifiers. The second part of the delegate declaration is a delegate keyword. A delegate keyword is a reserved word provided by the .NET Framework that is used to declare a delegate reference type. The third part of the delegate declaration is ReturnType which indicates the return type of the delegate reference type. The return type of the delegate reference type must be the same as the return type of the method we want to invoke. The fourth part of the delegate declaration is the DelegateName which indicates a user-defined name of the delegate reference type we want to declare. The user-defined name of a delegate reference type must follow the variables and methods naming convention of the .NET Framework. The fifth part of the delegate declaration is [ParameterList] which indicates the number of parameters of a delegate reference type. The parameters list of the delegate reference type must be the same as the parameters list of the method we want to invoke.

The Instantiation of Delegate Instances

The instantiation of a delegate instance is a process in which an instance of a delegate is referenced or associated with a method that has matching parameters and a return type. A method can be referenced or associated with an instance of the delegate by assigning that method to it as a parameter. When we define a custom delegate reference type using a delegate keyword then we declare an instance from it and instantiate it by assigning the target method to it as a parameter. When the method is assigned as a parameter to an instance of the delegate, it stores the memory address of that method and the method is referenced or associated with it. The following is the general syntax to declare and instantiate an instance of a delegate reference type.

C# Syntax

// Declare an instance of the Delegate reference type
DelegateName instanceName = null;

// Instantiate an instance of the Delegate reference type
instanceName = new DelegateName(MethodName)

The preceding declaration declares and instantiates an instance of the delegate reference type. The name of the declared instance is instanceName. The DelegateName indicates the name of the delegate reference type from which we declare an instance instanceName. The new keyword is used to instantiate the instance of the delegate. The MethodName represents the name of the method to be invoked by the delegate.

The Invocation of Methods

When a method is referenced or associated with an instance of the delegate then this is the last step in which we invoke that method by calling the associated instance of the delegate and assign values to its parameters, if the referenced or associated method takes parameters. The following is the general syntax to invoke a method using the referenced or associated delegate instance.

C# Syntax

ReturnType instanceName(ParametersList);

In the preceding declaration, the ReturnType represents the return type of the referenced or associated method, the instanceName represents the name of the delegate instance and the ParametersList represents the number of parameters of the referenced or associated method.

Types of Delegates

The delegates are categorized into the following two types.

  • Single Cast Delegates
  • Multicast Delegates

Single Cast Delegates

A single cast delegate is a type of delegate that references to a single method at a time. A single cast delegate holds the reference or the memory address of a single method that has the matching parameters and a return type. The following is an example of a single cast delegate type definition.

C# Example of Delegate type Definition

public delegate int myDelegate(int x);

The preceding declaration defines a delegate reference type myDelegate. The mydelegate is a user-defined name of the delegate that takes a single integer parameter and returns an integer value. Therefore, the myDelegate references and invokes a method that takes a single integer parameter and returns an integer value.

Program # 1

Write a program that invokes a simple static method using a delegate and displays a message in the method body. The method has no parameters list and no return type.

C# Program

using System;

namespace ProgramNamespace
{
    // Define a Delegate type that has no parameters list and no return type
    public delegate void dlgMessage();

    public class MainProgramClass
    {
        static void Main(string[] args)
        {
            // Declare an instance of the delegate reference type dlgMessage
            dlgMessage instDelegate = null;

            // Instantiate the delegate instance insDelegate by assigning a method
            instDelegate = new dlgMessage(displayMessage);

            // Invoke the method displayMessage() using the delegate instance instDelegate

            instDelegate();

            Console.WriteLine("Press any key to exit program");
            Console.ReadKey();
        }

        // Declare a method that has no parameters and no return type and display a message

        public static void displayMessage()
        {
            Console.WriteLine("Welcome to the .NET Delegates");
        }
    }
}

Program # 2

Write a program that invokes a non-static method of a class using a delegate. The method has no parameters list and it returns a string message to its calling point.

C# Program

using System;

namespace MainProgramNamespace
{
    // Define a Delegate type that has no parameters list and returns a string
    public delegate string dlgMessage();

    // Declare a class that contains a single nonstatic method. The method has no parameters list and returns a string message to its calling point

    public class MyMethodClass
    {
        // Declare a nonstatic method that has no parameters list and returns a string message to its calling point

        public string displayMessage()
        {
            return "Welcome to the .NET Delegates";
        }
    }

    public class MainProgramClass
    {
        static void Main(string[] args)
        {
            // Declare an instance of the class MyMethodClass
            MyMethodClass obj = new MyMethodClass();

            // Declare an instance of the delegate reference type dlgMessage
            dlgMessage instDelegate = null;

            // Instantiate the delegate instance insDelegate by assigning the non static method displayMessage() of the class MyMethodClass

            instDelegate = new dlgMessage(obj.displayMessage);

            // Invoke the method displayMessage() using the delegate instance instDelegate and declare a string variable that holds the return value of the displayMessage() method

            string msg = instDelegate();

            // Display the message

            Console.WriteLine(msg);

            Console.WriteLine("Press any key to exit program");
            Console.ReadKey();
        }
    }
}

The preceding program displays the message “Welcome to the .NET Delegates”. The program contains a delegate reference type dlgMessage and a method displayMessage. The delegate dlgMessage is a parameter-less delegate that does not take parameters and its return type is a string that returns a string value. The method displayMessage is a parameter-less user-defined method that is declared in the class MyMethodClass. The method display message returns a string “Welcome to the .NET Delegates”. In the main method of the program, we declared an instance of the delegate instDelegate. The parameters and the return types of the delegate dlgDelegate and the parameters and return type of the method displayMessage are the same. Therefore, the instance of the delegate instDelegate references and invokes the method displayMessage and displays a string message “Welcome to the .NET Delegates” on the screen.

Program # 3

Write a program that invokes a non-static method of a class using a delegate. The method takes two integer parameters and returns their sum to its calling point.

C# Program

using System;

namespace ProgramNamespace
{
    // Define a Delegate reference type that takes two integers parameters and returns an integer value

    public delegate int calculateTwoValues(int x, int y);

    // Declare a class that contains a single nonstatic method. The method has two integer parameters and returns their sum to its calling point

    public class MyMethodClass
    {
        // Declare a nonstatic method that takes two integer parameters and returns their sum to its calling point

        public int addValues(int x, int y)
        {
            return (x + y);
        }
    }
    public class MainProgramClass
    {
        static void Main(string[] args)
        {
            // Declare an instance of the class MyMethodClass
            MyMethodClass obj = new MyMethodClass();

            // Declare an instance of the delegate reference type
            calculateTwoValues instDelegate = null;

            // Instantiate the delegate instance insDelegate by assigning the non static method addValues() of the class MyMethodClass

            instDelegate = new calculateTwoValues(obj.addValues);

            // Invoke the method addValues() using the delegate instance instDelegate and declare an integer variable that holds the return value of the addValues() method

            int sumValue = instDelegate(10, 20);

            // Display the result of the addValues() method

            Console.WriteLine(sumValue);

            Console.WriteLine("Press any key to exit program");
            Console.ReadKey();
        }
    }
}

The preceding program calculates the sum of two integer values and displays their result. The program contains a delegate reference type calculateTwoValues and a method addValues that is defined in a class MyMethodClass. The delegate calculates two values takes two integer parameters and returns an integer value. The method addValues also takes two integer parameters and returns an integer value. The parameters and the return type of the delegate calculateTwoValues and the parameters and return type of the method addValues are the same. In the main method of the program, we declared an instance of the delegate reference type instDelegate. The instance instDelegate takes two integer values from the main method of the program and invokes the method and values. The method addValues calculates the sum of the two received values and returns the result back to the main method of the program. In the main method of the program, we declare an integer variable that stores the result of the method.

The Multicast Delegates

A multicast delegate is a type of delegate that references and invokes multiple methods at the same time. An instance of the multicast delegate reference type holds the references or the memory addresses of multiple methods that have the same parameters lists and the same return types as the parameters list and the return type of that of the delegate reference type. It means that the methods we want to invoke using a multicast delegate must have matching parameters and return types with the delegate reference type.

The declaration of a multicast delegate and a single cast delegate is the same but the main difference is that an instance of a single cast delegate reference type references and invokes a single method at a time whereas an instance of a multicast delegate reference type references and invokes multiple methods at the same time. The multicast delegate reference type is derived from the MulticastDelegate class which represents a multicast delegate type. The multicast delegate provides two operators, the += operator, and the -= operator, that are used to add to and remove from the reference of a method, respectively, of the instance of the multicast delegate reference type. The multicast delegate holds the reference of methods with a += operator and removes the reference of a method with a -= operator. The following is an example of a multicast delegate type definition.

C# Example of Delegate type Definition

public delegate void myDelegate(int x);

The preceding declaration defines a delegate type myDelegate. The myDelegate is a user-defined name of the delegate that takes a single integer parameter and its return type is void that does not return any value. The delegate myDelegate is a multicast delegate type that references and invokes multiple methods at the same time.

Program # 4

Write a program that invokes multiple methods using a multicast delegate. Declare three instance methods in a class and invoke these methods using a delegate from the main method of the program. The first method takes two integer values and returns their sum back to the main method, the second method takes two integer values and returns their difference back to the main method of the program and the third method takes two integer values and returns their multiplication to the main method of the program.

C# Program

using System;

namespace ProgramNamespace
{
    // Define a Multicast delegate reference type that takes two integers parameters
    public delegate void calculateTwoValues(int x, int y);

    // Declare a class that contains three user-defined methods
    public class MyMethodClass
    {
        public void AddValues(int x, int y)
        {
            Console.WriteLine("The sum of two values is");
            Console.WriteLine(x + y);
        }

        public void SubtractValues(int x, int y)
        {
            Console.WriteLine("The subtraction of two values is");
            Console.WriteLine(x - y);
        }

        public void MultiplyValues(int x, int y)
        {
            Console.WriteLine("The multiplication of two values is");
            Console.WriteLine(x * y);
        }
    }

    public class MainProgramClass
    {
        public static void Main()
        {
            // Declare an instance of the class MyMethodClass
            MyMethodClass obj = new MyMethodClass();

            // Declare an instance of the delegate reference type
            calculateTwoValues instDelegate = null;

            // Instantiate the multicast delegate using multiple methods
            instDelegate += new calculateTwoValues(obj.AddValues);
            instDelegate += new calculateTwoValues(obj.SubtractValues);
            instDelegate += new calculateTwoValues(obj.MultiplyValues);

            // Invoke the multiple methods using the instance of the multicast delegate and pass two integer values to all methods
            instDelegate(5, 2);

            Console.WriteLine("Press any key to exit program");
            Console.ReadKey();
        }
    }
}