Generic Delegates

Like methods, delegates can also be generic. To declare a generic delegate, use this general form:

delegate ret-type delegate-name(arg-list);

Notice the placement of the type parameter list. It immediately follows the delegate’s name. The advantage of generic delegates is that they let you define, in a type-safe manner, a generalized form that can then be matched to any compatible method.

The following program demonstrates a generic delegate called SomeOp that has one type parameter called T. It returns type T and takes an argument of type T.

Example

using System;
using System.IO;
namespace ConsoleApplication1
{
    // Declare a generic delegate.
    delegate T SomeOp<T>(T v);
    class GenDelegateDemo
    {
        // Return the summation of the argument.
        static int Sum(int v)
        {
            int result = 0;
            for (int i = v; i > 0; i--)
                result += i;
            return result;
        }
        // Return a string containing the reverse of the argument.
        static string Reflect(string str)
        {
            string result = "";
            foreach (char ch in str)
                result = ch + result;
            return result;
        }
        static void Main()
        {
            // Construct an int delegate.
            SomeOp<int> intDel = Sum;
            Console.WriteLine(intDel(3));
            // Construct a string delegate.
            SomeOp<string> strDel = Reflect;
            Console.WriteLine(strDel("Hello"));
        }
    }
}

Output

6
olleH

Let’s look closely at this program. First, notice how the SomeOp delegate is declared:

delegate T SomeOp<T>(T v);

Notice that T can be used as the return type even though the type parameter T is specified after the name SomeOp. Inside GenDelegateDemo, the methods Sum( ) and Reflect( ) are declared, as shown here:

static int Sum(int v) {
static string Reflect(string str) {

The Sum( ) method returns the summation of the integer value passed as an argument. The Reflect( ) method returns a string that is the reverse of the string passed as an argument. Inside Main( ), a delegate called intDel is instantiated and assigned a reference to Sum( ):

SomeOp<int> intDel = Sum;

Because Sum( ) takes an int argument and returns an int value, Sum( ) is compatible with an int instance of SomeOp.

In similar fashion, the delegate strDel is created and assigned a reference to Reflect( ):

SomeOp<string> strDel = Reflect;

Because Reflect( ) takes a string argument and returns a string result, it is compatible with the string version of SomeOp. Because of the type safety inherent in generics, you cannot assign incompatible methods to delegates. For example, assuming the preceding program, the following statement would be in error:

SomeOp<int> intDel = Reflect; // Error!

Because Reflect( ) takes a string argument and returns a string result, it cannot be assigned to an int version of SomeOp.