Raj Rao
Raj Rao

Reputation: 9138

Question about C# covariance

In the code below:

interface I1 { }
class CI1: I1 { }

List<CI1> listOfCI1 = new List<CI1>();

IEnumerable<I1> enumerableOfI1 = listOfCI1; //this works

IList<I1> listofI1 = listOfCI1; //this does not

I am able to assign my "listOfCI1" to an IEnumerable<I1> (due to covariance)

But why am I not able to assign it to an IList<I1>? For that matter, I cannot even do the following:

List<I1> listOfI12 = listOfCI1;

Shouldn't covariance allow me to assign a derived type to a base type?

Upvotes: 15

Views: 975

Answers (4)

Jon Skeet
Jon Skeet

Reputation: 1500485

Simply put, IList<T> is not covariant, whereas IEnumerable<T> is. Here's why...

Suppose IList<T> was covariant. The code below is clearly not type-safe... but where would you want the error to be?

IList<Apple> apples = new List<Apple>();
IList<Fruit> fruitBasket = apples;
fruitBasket.Add(new Banana()); // Aargh! Added a Banana to a bunch of Apples!
Apple apple = apples[0]; // This should be okay, but wouldn't be

For lots of detail on variance, see Eric Lippert's blog post series on it, or watch the video of my talk about variance from NDC.

Basically, variance is only ever allowed where it's guaranteed to be safe (and in a representation-preserving way, which is why you can't convert IEnumerable<int> into IEnumerable<object> - the boxing conversion doesn't preserve representation).

Upvotes: 24

Andrey
Andrey

Reputation: 60065

Compare declarations (msdn)

public interface IEnumerable<out T> : IEnumerable

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable

you see that magical word out? This means that covariance is on.

Upvotes: 5

Andrew Bezzub
Andrew Bezzub

Reputation: 16032

IList<T> interface is not covariant.

Upvotes: 1

SLaks
SLaks

Reputation: 887413

No.

Otherwise, you would then be able add a different implementation of I1 to a list that should only contain C1s.

Upvotes: 3

Related Questions