Look at Covariance and Contravariance in Delegates


In this article, we will look into Covariance and Contravariance in Delegates using C#. We know that delegate is type-safe function pointer referencing a method. Any method matching the delegate signature can be assigned to the delegate and can be called as a method. Once a delegate is assigned to a method, it behaves exactly as a method. Delegates provides below benefits:
  1. We can pass methods as parameters to other methods.
  2. To define callback methods.
  3. Multiple methods can be called with a single delegate.
C# provides a degree of flexibility when matching a delegate type with the method signature.  It doesn't require matching delegate signature exactly. Covariance allows us to have a more derived type as return type than specified in the delegate declaration. Similar way, Contravariance allows us to have less derived type as parameter type than specified in delegate. Let's see it with an example.

Covariance:

class parent
{
}
class child : parent
{
}
class Program
{
    public delegate parent CovarianceHandler();
    public static parent PCovariance()
    {
        return new parent();
    }
    public static child CCovariance()
    {
        return new child();
    }
    static void Main(string[] args)
    {
        CovarianceHandler handler = PCovariance;
        Console.WriteLine(handler().GetType().ToString());
        CovarianceHandler handler1 = CCovariance;
        Console.WriteLine(handler1().GetType().ToString());
    }
}

Because of Covariance, we are able to call method that is having return type[child] derived from return type[parent] in delegate declaration. 

Contravariance:

class parent
{
}
class child : parent
{
}
class Program
{
    public delegate parent ContravarianceHandler(child c);
    public static parent PContravariance(parent p)
    {
        return p;
    }
    public static parent CContravariance(child c)
    {
        return c as parent;
    }
    static void Main(string[] args)
    {
        ContravarianceHandler handler = PContravariance;
        Console.WriteLine(handler(new child()).GetType().ToString());
        ContravarianceHandler handler1 = CContravariance;
        Console.WriteLine(handler1(new child()).GetType().ToString());
    }
}

Here, we are able to call PContravariance having parameter type [parent] less derived than the type declared in delegate signature using ContraVariance. By using this, we can have a single event handler having base type as parameter type and use it with methods having derived type as parameter type for calling.

I am ending the things here. I hope this article will be helpful for all.

Up Next
    Ebook Download
    View all
    Learn
    View all