Why classes that implement variant interfaces remain invariant?
c#, c#-4.0, covariance, ienumerable
Solution
Firstly, classes are always invariant in C#. You can't declare a class like this:
// Invalid
public class Foo<out T>
Secondly - and more importantly for the example you've given - `List<T>` couldn't be declared to be covariant or contravariant in `T` anyway, as it has members both accepting and returning values of type `T`.
Imagine if it were covariant. Then you could write this (for the obvious `Fruit` class hierarchy):
List<Banana> bunchOfBananas = new List<Banana>();
// This would be valid if List<T> were covariant in T
List<Fruit> fruitBowl = bunchOfBananas;
fruitBowl.Add(new Apple());
Banana banana = bunchOfBananas[0];
What would you expect that last line to do? Fundamentally, you shouldn't be able to add an `Apple` reference to an object whose actual execution-time type is `List<Banana>`. If you add an apple to a bunch of bananas, it falls off. Believe me, I've tried.
The last line should be safe in terms of types - the only values within a `List<Banana>` should be `null` or references to instances of `Banana` or a subclass.
Now as for why classes can't be covariant even when they could logically be... I believe that introduces problems at the implementation level, and would also be very restrictive at the programming level as well. For example, consider this:
public class Foo<out T> // Imagine if this were valid
{
private T value;
public T Value { get { return value; } }
public Foo(T value)
{
this.value = value;
}
}
That would still probably have to be invalid - the variable is still writable, meaning it counts as an "in" slot. You'd have to make every variable of type `T` read-only... and that's just for starters. I strongly suspect that there would be deeper problems.
In terms of pure pragmatism, the CLR has supported delegate and interface variance from v2 - C# 4 just introduced the syntax to expose the feature. I don't believe the CLR has ever supported generic class variance.
Problem
C# 4.0 has extended the co and contravariance further for generic types and interfaces. Some interfaces (like `IEnumerable<T>`) are covariants, so I can do things like: ``` IEnumerable<object> ie = new List<string>(); ``` but what about this line? I got a compile-time error ``` List<Object> list = new List<String>(); //Cannot implicitly convert type List<string>' to List<object>' ``` I mean, if `List<T>` implement `IEnumerable<T>` why `List<T>` is still invariant? Is out there a good counterexample that explain why this should not be allowed in C#?