Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Covariance and Contravariance

So here is something that came up in a discussion I was having.  It revolved around delegates and their parameter types because we were trying to find an easier way to solve an issue without having to write more code than we really wanted to.  If you program entirely in VB or are not using .Net framework 2.0 with C#, then you are missing out on 2 features of delegates that are very useful: covariance and contravariance.  Now I have personally spent, until very recently, the vast majority of my time in VB and Framework 1.1, so even though I knew about the features, I never fully understood what I could do with them and I was never able to make use of them until now when it came up as part of a way to solve a problem in a program that I am helping a friend with.  He knew nothing of these new features, so maybe there are more of you out there that benefit from this, as it doesn’t seem to be well documented in easy to find places.  Just for fun I tried to google "covariance" and a few other things with no success, so maybe putting this out there will make it easier for others to find.  These are fine examples of how the languages continue to evolve and allow us to create more flexible, maintainable and efficient code.

Covariance basically means that the return value of a method that is referenced by your delegate can have a different return type than that specified by the delegate itself, so long as the return type of the method is a subclass of the return type of the delegate.  In the example below, you can see that MyMethod returns Car, but xyz is calling FunctionTwo, which returns type Toyota.  Because Toyota is derived from Car, this works.

Covariance
public class Car
{ } public class Toyota : Car
{ } class Demo
{ static void Main() { MyMethod abc = FunctionOne; MyMethod xyz = FunctionTwo; } public delegate Car MyMethod(); public static Car FunctionOne() { return new Car(); } public static Toyota FunctionTwo() { return new Toyota(); } }

 

Contravariance is kind of the same thing, but deals with the parameters rather than return types.  Contravariance allows you to use delegate parameters who’s types are those that inherit from the parameter types used in the method the delegate references.  In the following example, you can see that FunctionOne specifies the Car type as the parameter, while the delegate has the signature that specifies Toyota.  Contravariance allows this to happen.

Contravariance
class Demo
{ public delegate void MyMethod(Toyota value); static void Main(string[] args) { MyMethod abc = FunctionOne; MyMethod xyz = FunctionTwo; } public static void FunctionOne(Car value) { } public static void FunctionTwo(Toyota value) { } }
This entry was posted in .Net Development, Patterns and Practices. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

12 Responses to Covariance and Contravariance

  1. Srikanth says:

    Raymond, your explanation is very neat and precise. This is the best covariance and contravariance explanation on the Internet.

  2. Srikanth says:

    Raymond, your explanation is very neat and precise. This is the best covariance and contravariance explanation on the Internet.

  3. Chintan Shah says:

    Very nice post.

  4. Rejani says:

    Good article.

  5. Vicente says:

    Hello:
    I have a question:
    Suppose I have a delegate D and a class A which implements(not inherits) more than two overloads of a method M. Suppose that none of these overloads match exactly the signature of D, but all of them are elegible for D due to Covariance and Contravariance.
    Which overload wins?

  6. John Thompson says:

    Thanks for the explaination Raymond!
    I had not heard these terms before either, but the technique makes sense.

    At least Covariance does, anyway. This is as you say just a utilization of polymorphism.

    Controvariance surprised me though. At first I was confused by the fact that a base class of a parameter type would likely have a limited interface relative to the class defined in the delegate parameter list. But then I realized this should not be a problem, because we are only dealing with a delegate parameter which defines a type not an interface. Still assigning a function with a base class parameter type to the delegate seems unusual or at least less useful than assigning sub class. This would seem to imply that you could define your delegated function as:

    public void FunctionX(Object value)

    My gut reaction is that this seems to undermine the principles of strong typing. Maybe I just need to think about it some more.

    Could you also assign a function with a sub class parameter type? Would this still be defined as contravariance or another example of covariance?

  7. rlewallen says:

    Derick,

    This isn’t really polymorphism, but rather it supports polymorphic behavior of objects.

  8. Isn’t this just a fancy way of saying “Polymorphism”?

    I understand the benefit of using delegates like this, though… I had never tried doing that before and I’ll definitely benifit from knowing about this. Thanks for the good post.

  9. Dave Redding says:

    I can see how that would make sense. Thanks for the reply!

    Happy new year!

    Dave.

  10. simone_b says:

    Thanks for the clear explanation Raymond

  11. rlewallen says:

    Dave,

    A better example would be a method that accepts EventArgs, but you have 2 delegates, one that has a KeyEventArgs and another that has MouseEventArgs. When some body presses a key or clicks the mouse, you want the same action to happen, so you reference both delegates to the same method because the method EventArgs is a parent class of the delegate’s eventargs. This is the example I believe Microsoft docs use if I remember correctly.

  12. Dave Redding says:

    These are new terms to me, thanks for the tech tip. One question I have to ask though is, won’t contravariance violate some of the purposes of having a delegate?

    I do see the usefullness of it, but it seems to be one of those aqward “Could be done better a different way” type of things. For instance, why would’nt i change my parameter type to car, instead of specifying toyota if i know that i’m going to have a function that accepts any kind of “Car” object?

    Thanks for the great post!

Leave a Reply