No, your example wouldn't work for three reasons:
- Classes (such as
List<T>
) are invariant; only delegates and interfaces are variant - For variance to work, the interface has to only use the type parameter in one direction (in for contravariance, out for covariance)
- Value types aren't supported as type arguments for variance - so there's no converstion from
IEnumerable<int>
toIEnumerable<object>
for example
(The code fails to compile in both C# 3.0 and 4.0 - there's no exception.)
So this would work:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
The CLR just uses the reference, unchanged - no new objects are created. So if you called objects.GetType()
you'd still get List<string>
.
I believe it wasn't introduced earlier because the language designers still had to work out the details of how to expose it - it's been in the CLR since v2.
The benefits are the same as other times where you want to be able to use one type as another. To use the same example I used last Saturday, if you've got something implements IComparer<Shape>
to compare shapes by area, it's crazy that you can't use that to sort a List<Circle>
- if it can compare any two shapes, it can certainly compare any two circles. As of C# 4, there'd be a contravariant conversion from IComparer<Shape>
to IComparer<Circle>
so you could call circles.Sort(areaComparer)
.