C#. Generic delegates

Generic delegates

Before exploring this topic, it is recommended that you familiarize yourself with the following topics:


Contents


Search other resources:




1. Generalized delegates. Features of use. Syntax for declaring a generic delegate for multiple types

C# allows the use of generic delegates that receive generic types as parameters. The advantage of generic delegates is that a typed generic form of a method is created, which is then matched to a specific method of any class. A method that matches a generic delegate must have a similar signature. Concrete methods can be either static methods or instance methods.

Generic delegates allow you to safely call any method that conforms to its generic form.

The general form of declaring a generic delegate is as follows:

delegate return_type DelegateName<T1, T2, ..., TN>(arguments_list);

here

  • DelegateName – the name of the generic delegate;
  • T1, T2, TN – the names of the types that the delegate operates on;
  • arguments_list – the list of arguments that the delegate receives.

After such a declaration, you can create a reference to a generic delegate in the following form:

DelegateName<T1, T2, ..., TN> refDelegate<type1, type2, ..., typeN>;

here

  • DelegateName<T1, T2, …, TN> – type name of generic delegate;
  • refDelegate – the name of the generic delegate reference;
  • type1, type2, typeN – names of types declared in the program or names of basic types (int, char, string, etc.).

If a reference is declared, then this reference can be assigned the name of a compatible method something like this:

refDelegate = obj.MethodName;

here

  • obj – the name of the instance of the class containing the MethodName() method;
  • MethodName – the name of the method that is compatible with the DelegateName delegate. Compatibility means that the number and types of parameters for a method and a delegate are the same.

After the reference points to the method, it is possible to call this method in the usual way.

refDelegate(arguments_list);

here

  • arguments_list – a list of arguments passed to the MethodName() method, which is called by refDelegate.

 

2. Syntax for declaring a generic delegate for one type T

If a delegate is declared for only one generic type T, then the general form of such a declaration is as follows

delegate return_type DelegateName<T>(arguments_list);

here

  • DelegateName – the name of generic delegate;
  • T – the name of the generic delegate type;
  • arguments_list – the list of arguments that the delegate receives.

Accordingly, the declaration of a reference to the delegate DelegateName<T> and its use can be as follows

refDelegate = obj.MethodName;
...
refDelegate(arguments_list);

here

  • refDelegate – a reference to the delegate DelegateName<T>;
  • arguments_list – a list of arguments passed to the MethodName method.

 

3. An example of a generic delegate that takes one type T as a parameter

The example declares a generic delegate Equal<T> that operates on type T and receives two parameters of type T. The delegate returns a bool value that determines the equality (inequality) of the two received parameters.

The EqualOperations class is also declared, which contains the implementation of the EqualInt(), EqualShort(), and EqualString() methods. These methods determine equality for int, short, and string, respectively. The methods are compatible with the Equal<T> delegate type.

using System;

namespace ConsoleApp19
{
  // Generic delegate
  delegate bool Equal<T>(T value1, T value2);

  // A class containing methods that are compatible with the Equal<T> delegate
  class EqualOperations
  {
    // For int type
    public bool EqualInt(int value1, int value2)
    {
      return value1 == value2;
    }

    // For short type
    public bool EqualShort(short value1, short value2)
    {
      return value1 == value2;
    }

    // For string type
    public bool EqualString(string value1, string value2)
    {
      return value1 == value2;
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Declare an instance of the EqualOperations class
      EqualOperations obj = new EqualOperations();

      // 2. Using delegate for int type
      // 2.1. Construct a delegate named delInt for type int
      Equal<int> delInt = obj.EqualInt;

      // 2.2. Call method using delegate for int type
      bool equalInt = delInt(5, 5);
      Console.WriteLine("equalInt(5,5) = {0}", equalInt);

      // 3. Using a delegate for the string type
      // 3.1. Construct a delegate named delString
      Equal<string> delString = obj.EqualString;

      // 3.2. Call a method using delegate for the string type
      bool equalString = delString("bestprog.net", "bestprog");
      Console.WriteLine("equalString = {0}", equalString);

      Console.ReadKey();
    }
  }
}

The result of the program

equalInt(5,5) = True
equalString = False

 

4. An example of a generic delegate that takes two types T1, T2 as parameters

The example declares a delegate using two types T1, T2.

using System;

namespace ConsoleApp19
{
  // Delegate using two types T1, T2
  delegate void Operation<T1, T2>(T1 value1, T2 value2);

  // A class containing a method that agrees with the Operation<T1, T2> delegate
  class Methods
  {
    public void Print(int value1, double value2)
    {
      Console.WriteLine("value1 = {0}", value1);
      Console.WriteLine("value2 = {0}", value2);
    }
  }

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

      // Declare a reference to the delegate Operation<T1, T2>
      Operation<int, double> refOp;

      // Assign the address of the Print() method to refOp
      refOp = obj.Print;

      // Call the Print() method using refOp reference
      refOp(23, 8.89);

      Console.ReadKey();
    }
  }
}

The result of the program

value1 = 23
value2 = 8.89

 

5. An example of declaring and using generic delegate that is consistent with static methods

A generic delegate can be applied to static methods. The example declares a delegate to ensure compatibility with static methods that implement finding the minimum value for the int and double types. The main() function demonstrates the use of the Min<T> delegate.

using System;

namespace ConsoleApp19
{
  // Generic delegate that receives an array of generic type T
  // and returns the value of type T
  delegate T Min<T>(T[] array);

  // A class containing methods for finding the minimum value
  // in an array for different numeric types
  class MinValues
  {
    // Finding the minimum value in an array of type double
    public static double GetMinDouble(double[] array)
    {
      double min = array[0];
      for (int i = 1; i < array.Length; i++)
        if (min > array[i])
          min = array[i];
      return min;
    }

    // For type int
    public static int GetMinInt(int[] array)
    {
      int min = array[0];
      for (int i = 1; i < array.Length; i++)
        if (min > array[i])
          min = array[i];
      return min;
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. Using the Min<T> delegate for the double type.
      // 1.1. Declare a testable array of type double
      double[] AD = { 2.3, 2.5, 1.8, 1.1, 2.8, 1.9 };

      // 1.2. Declare a reference to the Min<T> delegate for type double
      Min<double> refDouble;

      // 1.3. Assign a static method to the reference
      refDouble = MinValues.GetMinDouble;

      // 1.4. Call the GetMinDouble() method by reference refDouble
      double minDouble = refDouble(AD);
      Console.WriteLine("minDouble = {0}", minDouble);

      // 2. Using a delegate for int type
      // 2.1. Declare the array under test
      int[] AI = { 22, 33, 13, 18, 19, 140, 18, 10, 134 };

      // 2.2. Declare a reference to the Min<T> delegate for type int
      //      and assign the static GetMinInt method to it
      Min<int> refInt = MinValues.GetMinInt;

      // 2.3. Call the GetMinInt method by reference refInt
      int minInt = refInt(AI);
      Console.WriteLine("minInt = {0}", minInt);

      Console.ReadKey();
    }
  }
}

After starting the program will give the following result

minDouble = 1.1
minInt = 10

 


Related topics