The assignment compatibility is preserved. Know that:
Invariant means, must use the exact type – be ‘in’ or ‘out’
Covariant means, parameter type can be of a derived class type; upcast’able; more specific to more general. Specified as output types: return types, 'out' params, get properties. Array types fall in this category.
Contravariant is opposite of covariance. Parameter type can be a parent class type; downcast'able; more general to specific type. Use base type where a child type was expected. Specified as input types: set, 'in' parameters, etc.
Covariance and contravariance (or simply “variance”) are advanced concepts. The motivation behind introducing and enhancing variance in C# was to allow generic interface and generic types (in particular, those defined in the Framework, such as IEnumerable<T>() to work more as we would expect.
Conventionally, array types are covariant. This means that X can be cast to Y if X subclasses Y. For instance:
The downside of this reusability is that element assignments can fail at runtime:
Covariance (and contra variance) in interfaces is something that you typically consume: it’s less common that you need to write variant interfaces.
See following example:
The type system is free to allow us to safely upcast and downcast between those interfaces in the direction indicated by the keyword. You might like exploring more here.
It's really not a "save the day" sort of feature. It's more of a "it works the way I expect it to" feature - Eric LippertEnjoy, variants in life! (0: