Home > .Net 4.0, CodeProject > Understanding Covariance and Contravariance in .Net 4.0

Understanding Covariance and Contravariance in .Net 4.0

A couple of years back while working on a project, I got a compilation exception related to generics.

I had a base class “BaseVO” and classes deriving from BaseVO . for e.g “FlightVO : BaseVO”.My idealistic assumption was that since: “FlightVO” inherits from BaseVO , and since BaseVO b = new FlightVO() is valid as per inheritance, then

“List<BaseVO>  lstBaseVO = new List<FlightVO>() would also be valid.”

But duh !!! , instead I get a compilation exception that says,
Argument ’1′: cannot convert from ‘System.Collections.Generic.List<ValueObjects.FlightVO>’ to ‘System.Collections.Generic.List<ValueObjects.BaseVO>’

Since I was so sure about my assumption being right, I posted it on the msdn forum just to confirm that it was a “BUG” :-) in Generics.
Thread in MSDN forum: http://social.msdn.microsoft.com/Forums/bg-BG/netfxbcl/thread/e4863bda-3f24-4a28-af55-230baaff5e7b .
Those were the .Net 3.0 days and one of the MVP moderators gave a pretty good explanation as to why my assumption was wrong.Here’s his explanation:

List<Base> and List<Derived> are distinct types, you can’t convert List<Derived> to List<Base>.  If it were possible, you could pass a List<Derived> to a method accepting List<Base> and that method could add an object of type Base to the list,  Which violates the promise that the original list only contains objects of type Derived

I assume, someone in the CLR team might have found my assumption quite viable and it got shape in .Net 4.0 as “Covariance and Contravariance in generics” :-).

So the above case is a valid example where “Covariance in Generics” can be used.

However, if we compile List<BaseVO>  lstBaseVO = new List<FlightVO>() in .Net 4.0, it would still give the same compilation error for the very explanation given by our MVP friend. In order to make it covariant compliant, our modified piece of code would look like ,

IEnumerable< BaseVO > lstBaseVO = new List< FlightVO >();

The above statement is valid because, in .Net 4.0, List<T> : IEnumerable<out T> where type ‘T’ is marked as covariant.

Here’s a quick summarization about variance in Generics.

  1. What are the programming constructs where covariance and contravariance are applicable ? Variant type parameters are restricted to generic interface and generic delegate types thereby ensuring type safety.
  2. In what scenarios would we want to use variance in Generics? Lets look at a code snippet

covariance example

So, covariance and contravariance of generic type parameters enable us to use constructed generic types [A<Athlete>] whose type arguments [Athlete] are more derived (covariance) or less derived (contravariance) than the type argument [Person] of a target constructed type [ISample<Person>].

Covariance seems very natural because it behaves like polymorphism, whereas Contravariance seems counterintuitive.One thing that we need to be clear about is that both Covariance and Contravariance both adhere to the thumb rule of “Inheritance” which says,

“A Derived class instance can be assigned to a Base class variable”

Now, Let’s look at a Contravariance example.

contravariiance1

line 2 of code snippet might make you feel that the thumb rule of inheritance is being violated.i.e. Derived class variable d is being assigned an instance of Base class.

However, that isn’t case .Let’s understand each line of the code snippet.

contravariiance2

contravariiance4

contravariiance3

In general, a covariant type parameter can be used as the return type of a generic delegate/interface, and contravariant type parameters can be used as input parameter types.

A brief summary of facts about variance in the common language runtime:

1. A generic interface or generic delegate type can have both covariant and contravariant type parameters.

2. Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.

3. How do we define variant generic interfaces and delegates?

Starting with the .NET Framework 4, Visual Basic and C# have keywords that enable you to mark the generic type parameters of interfaces and delegates as covariant or contravariant.

  • A covariant type parameter is marked with the out keyword. You cannot use a covariant type parameter as a generic type constraint for interface methods. for e.g T Display<out T>(); is an invalid statement.
  • A contravariant type parameter is marked with the in keyword. You can use a contravariant type parameter as a generic type constraint for an interface method.

Thank you :-)

Download code sample: Variance_in_Generics

About these ads
  1. Sharad Chatak
    September 13, 2011 at 6:35 am | #1

    Nice giri, Thanks for sharing

  2. Abhijeet Haval
    September 13, 2011 at 11:29 am | #2

    Thats fantastic.
    I remember I also got the compilation error and then browsed the net.
    This is really exciting feature in .Net 4.0.
    Thanks for sharing. Looking forward for your other posts.

  3. Ajay Maurya
    September 14, 2011 at 5:50 pm | #3

    A Very nice topic giri. I used this a lot while doing one silverlight project but was not exactly aware of the reason behind IEnumerable lstBaseVO = new List(); like declaration.

    Thanks for sharing :)

  4. April 5, 2012 at 12:50 pm | #4

    Nice article. thanks for sharing. I could not able to view the image used for code snippet however. Could you please add those images?

    Thanks,
    -Ashwath

  5. April 5, 2012 at 12:51 pm | #5

    Nice article. Thanks for sharing. I could not able to see the images used for code snippet. Could you please add those images?

    -Ashwath

    • April 5, 2012 at 1:17 pm | #6

      Thanks Ashwath for your feedback & good to know that you found the article helpful. However, I have checked the post using different browsers and am able to view all the images . Would like to know which browser (and version) are you using to view the site. Also, you can download the code snippet from http://bit.ly/ota6ix

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: