I am writing this post only in order to experiment spelling of covariance and contravariance. What if Shakespeare was a computer geek and wanted to develop a new language? “To sleep, perchance to dream” this looks more like PerlScript to me than English!
These terms lead to other terms like variant and invariant. However, thou shall not be freaked out. They are simpler than they appear:
Covariance is this (a type will be automatically converted to a more general type):
object str = "string";
Contravariance is the opposite. In C#, method group to delegate conversions are covariant in return types, and contravariant in argument types.
Generic delegate types are always invariant in C# 3.0 which means they can not be automatically converted to more or less generic types, but C# 4.0 allows declaration of covariance and contravariance on parameterized interface and delegate types.
This post describes this new feature of C# 4.0 in more detail.
In previous versions of C#, generic types are invariant. That is, for any two types
GenericType<T>
andGenericType<K>
, in whichT
is a subclass ofK
orK
is a subclass ofT
,GenericType<T>
andGenericType<K>
have no inheritance relationship whatsoever to each other. On the other hand, ifT
is a subclass ofK
and if C# supports covariance,GenericType<T>
is also a subclass ofGenericType<K>
or if C# supports contravariance,GenericType<T>
is a superclass ofGenericType<K>
.
It continues:
Fortunately, C# 4.0 provides us an option: if a generics interface or generics delegate which has a reference type
T
as its type parameter and does not have any method or member that take in a parameter of typeT
, we can declare it to be covariant on T. On the other hand, if that interface or delegate does not have any method or member that returning T, we can declare it be contravariant on T. (Notice the emphases, only interfaces and delegates have covariance and contravariance support and the type parameter must be a reference type. On the other hand, C# arrays have been supporting covariance from the very beginning.)
In simple words, now you can do this:
interface ISampleGenerator<T> { public IEnumerable<T> MakeSamples(int count); } //Assuming some implementation of interface var objects = (ISampleGenerator<object>)new StringSampleGenerator<String>(); foreach(var a in objects){ //a is object here }
Note that this covariance is possible only if the interface has absolute no input dependency on the type T.
Leave a Reply