Now, to my untrained eye, covariance seems to be the same as upcasting, except that it refers the casting of collections. (And of a similar statement can be made regarding contravariance and downcasting).
Is it really that simple?
Covariance isn't about upcasting, although I can see why you think it's related.
Covariance is about the following very simple idea. Let's say you have a variable derivedSequence
of type IEnumerable<Derived>
. Let's say you have a variable baseSequence
of type IEnumerable<Base>
. Here, Derived
derives from Base
. Then, with covariance, the following is a legal assignment, and an implicit reference conversion occurs:
baseSequence = derivedSequence;
Note that this is not upcasting. It is not the case that IEnumerable<Derived>
derives from IEnumerable<Base>
. Rather, it is covariance that allows you to assign the value of the variable derivedSequence
to the variable baseSequence
. The idea is that variables of type Base
can be assigned from objects of type Derived
, and since IEnumerable<T>
is covariant in its parameter, objects of type IEnumerable<Derived>
can be assigned to variables of type IEnumerable<Base>
.
Of course, I haven't yet really explained what covariance is. In general, covariance is about the following simple idea. Let's say you have a mapping F
from types to types (I'll denote this mapping by F<T>
; given a type T
its image under the mapping F
is F<T>
.) Let's say that this mapping has the following very special property:
if X
is assignment compatible with Y
, then F<X>
is assignment compatible with F<Y>
as well.
In this case, we say that F
is covariant in its parameter T
. (Here, to say that "A
is assignment compatible with B
" where A
and B
are reference types means that instances of B
can be stored in variables of type A
.)
In our case, IEnumerable<T>
in C# 4.0, an implicit reference conversion from instances of IEnumerable<Derived>
to IEnumerable<Base>
if Derived
is derived from Base
. The direction of assignment compatibility is preserved, and this is why we say that IEnumerable<T>
is covariant in its type parameter.