I generally understand interfaces, inheritance and polymorphism, but one thing has me puzzled.
In this example, Cat implements IAnimal and of course List implements IList:
IList<IAnimal> cats = new List<Cat>();
but it generates a compilation error (Cannot implicitly convert type…). It also won’t work if I use an asbtract superclass [Animal] that Cat inherits from. However, If I replace IAnimal with Cat:
IList<Cat> cats = new List<Cat>();
it compiles fine.
In my mind, because Cat implements IAnimal, the first example should be acceptable, allowing us to return an interface for both the list and the contained type.
Can anyone explain why it isn’t valid? I’m sure there’s a logical explanation.
There is a logical explanation, and this exact question is asked pretty much every day on StackOverflow.
Suppose this was legal:
What stops this from being legal?
Nothing. “cats” is a list of animals, and a giraffe is an animal, and therefore you can add a giraffe to a list of cats.
Clearly that is not typesafe.
In C# 4 we added a feature whereby you can do that if the metadata annotations allow the compiler to prove that it is typesafe. In C# 4 you can do this:
because
IEnumerable<IAnimal>has no Add method, so there is no way to violate type safety.See my series of articles on how we designed this feature in C# 4 for more details.
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/default.aspx
(Start from the bottom.)