Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is covariance not allowed with ReadOnlyCollection?

The reason this code works is due to the fact that the Enumerator cannot modify the collection:

var roList = new List<string>() { "One", "Two", "Three" };
IEnumerable<object> objEnum = roList;

If we try to do the same thing with a List<object>, instead of IEnumerable<object>, we would get a compiler error telling us that we cannot implicitly convert type List<string> to List<object>. Alright, that one makes sense and it was a good decision by Microsoft, in my opinion, as a lesson learned from arrays.

However, what I can't figure out is why in the world is this hardline rule applicable to something like ReadOnlyCollection? We won't be able to modify the elements in the ReadOnlyCollection, so what is the safety concern that caused Microsoft to prevent us from using covariance with something that's read-only? Is there a possible way of modifying that type of collection that Microsoft was trying to account for, such as through pointers?

like image 707
B.K. Avatar asked Aug 29 '14 20:08

B.K.


1 Answers

Variance and contravariance only work on interfaces and delegates, not on classes.

However, you can do that (using .NET 4.5):

ReadOnlyCollection<string> roList = ...
IReadOnlyCollection<object> objects = roList;

(because IReadOnlyCollection<T> is covariant)


To answer your question about why variance isn't allowed on classes, here's Jon Skeet's explanation from his C# in Depth book (second edition, §13.3.5, page 394).

NO VARIANCE FOR TYPE PARAMETERS IN CLASSES

Only interfaces and delegates can have variant type parameters. Even if you have a class that only uses the type parameter for input (or only uses it for output), you can’t specify the in or out modifiers. For example Comparer<T>, the common implementation of IComparer<T>, is invariant — there’s no conversion from Comparer<IShape> to Comparer<Circle>.

Aside from any implementation difficulties that this might’ve incurred, I’d say it makes a certain amount of sense conceptually. Interfaces represent a way of looking at an object from a particular perspective, whereas classes are more rooted in the object’s actual type. This argument is weakened somewhat by inheritance letting you treat an object as an instance of any of the classes in it s inheritance hierarchy, admittedly. Either way, the CLR doesn’t allow it.

like image 184
Thomas Levesque Avatar answered Nov 15 '22 19:11

Thomas Levesque