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:

We can pass methods as parameters to other methods.

To define callback methods.

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:

classparent

{

}

classchild : parent

{

}

classProgram

{

publicdelegateparentCovarianceHandler();

publicstaticparent PCovariance()

{

returnnewparent();

}

publicstaticchild CCovariance()

{

returnnewchild();

}

staticvoid 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:

classparent

{

}

classchild : parent

{

}

classProgram

{

publicdelegateparentContravarianceHandler(child c);

publicstaticparent PContravariance(parent
p)

{

return p;

}

publicstaticparent CContravariance(child
c)

{

return c asparent;

}

staticvoid Main(string[] args)

{

ContravarianceHandler handler = PContravariance;

Console.WriteLine(handler(newchild()).GetType().ToString());

ContravarianceHandler handler1 = CContravariance;

Console.WriteLine(handler1(newchild()).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.