List<B>
simply is not a subtype of List<A>
. (I'm never sure about what "covariant" and what "contravariant" is in this context so I'll stick with "subtype".) Consider the case where you do this:
void Fun(List<A> aa) {
aa(new A());
}
var bb = new List<B>();
Fun(bb); // whoopsie
If what you want to do was allowed it would be possible to add an A
to a list of B
s which is clearly not type-safe.
Now, clearly it's possible to read elements from the list safely, which is why C# lets you create covariant (i.e. "read-only") interfaces - which let the compiler know it's not possible to cause this sort of corruption through them. If you only need read access, for collections, the usual one is IEnumerable<T>
, so in your case you might just make the method:
void Fun(IEnumerable<A> aa) { ... }
and use the Enumerable
methods - most should be optimised if the underlying type is List
.
Unfortunately, because of how the C# generics stuff works, classes can't be variant at all, only interfaces. And as far as I know, all the collection interfaces "richer" than IEnumerable<T>
are "read-write". You could technically make your own covariant wrapper interface that only exposes the read operations you want.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…