Make it a little easier to understand:
abstract class Animal {}
Suppose this was legal. What stops this?
class Shark : Animal {}
firstCage is of type Cage<Animal> , which means that it can contain any animal. But in fact, we know that this is a cage only for tigers. You just put the shark in a tiger cage, which seems uncomfortable for both the shark and the tiger.
Obviously this is not possible. What is in the way? The only thing that prevents it is that first of all, put the tiger cage in the collection of animals. A tiger cage is not some kind of animal cage, because there are things you can do with an animal cage that you cannot do with a tiger cage, namely, insert a shark into it. The basic principle of object-oriented design is that subtypes can do everything their supertypes can do; a tiger cage cannot do everything an animal cage can do, so it is not a subtype.
The higher the likelihood that generic types cannot be covariant in their type arguments, because it violates the Liskov Substitution Principle. In C # 4, some interfaces and delegates are covariant in their type arguments. For example, in C # 4 it is legal to put IEnumerable<Tiger> in List<IEnumerable<Animal>>> , because it cannot be dangerous. We can support the principle of substitution by allowing covariance, because IEnumerable<T> is the "external" interface. Do you only ever choose tigers; there is no way to place sharks.
source share