Variance generickych typu
Definice. Necht B je typove kompatibilni s A, typicky pokud B dedi od A. Muzu udelat A a = new B(); Potom typ C<T> je
- covariantni podle T$\equiv$C<B>je typove kompatibilni sC<A>
- contravariantni podle T$\equiv$C<A>je typove kompatibilni sC<B>
- invariantni podle T$\equiv$C<A>aC<B>nejsou typove kompatibilni
Trochu lidsky
- Covariant - muzu do pole objectů přiřadit pole Persons (neco lepsiho)
- Contravariant - můžu do neceho lepsiho přiřadit něco horšího
- Invariant - nemůžu přiřadit nic jiného
Priklady:
- pole referencí je covariant, ale pole hodnot není
    - vyhoda kovariance: muzu psat obecnejsi kod
- nevyhoda: vetsinou kdyz pracuji s pole referenci, tak kovarianci nevyuziju, ale stejne za to musim zaplatit. Tim ze povoluju kovarianci, se musi vzdy pri zapisu do pole delat run-time check. Takze zapis do pole referenci je asi o 20% pomalejsi nez zapis do pole hodnot. Pri optimalizaci se muze vyplatit ty referencni typy zabalit do nejakeho hodnotoveho typu a definovat implicitni konverze.
 
string[] sa = new string[10];
object[] so = sa;  // ok --> covariant
oa[0] = "Hello";  // ok
oa[1] = 5;  // prelozi se, ale pri behu to spadne
- List je invariantni. Nemůžu udělat toto:
class A {...}
class B : A {...}
var a = new List<A>();
a = new List<B>();  // error
var o = new List<object>();
o = a;  // error
Ale bylo by to fajn. Možná nás zachrání interface IList<T>. Umí věci typu Count a indexovat.
Generické interfacy lze explicitně označit za covariant / contravariant. Ale jen pro refereční typy!!!
interface I1<T> {...}   // invariant
interface I2<out T> {   // covariant
    public T m();
    public void m(T a);  // error
}
interface I3<in T> {    // contravariant
    public T m();   // error
    public void m(T a);
}
interface I4<out T1, T2, in T3, in T4> {...}
I<A, B, C:G, D:H> = I<A/E:A, B, C/G, D/H>
Z toho plyne, že IList<T> musí být invariantní, protože má nějakou indexovací metodu, který bude mít setter (in T) a getter (out T).
Takže je potřeba nějaký interface, který je jen readonly… proto existuje IReadOnlyList, takže do IReadOnlyList<object> můžu předat cokoliv co ho implementuje… pole a list referenčních typů.
K čemu je sakra contravariance?
Pozor, tohle neni IComparable! c# má interface IComparer, který umí comparovat.
interface IComparer<in T> {
    int compare(T i1, T, i2);
}
abstract class Animal { string Name; int weight; }
class Cat : Animal { int Fluffiness }
class Elephant : Animal { int TrunkLength }
class AnimalWeightComparer : IComparer<Animal> {...}
class CatFluffinessComparer : IComparer<Cat> {...}
static void OrganizeCatCompetition(Cat c1, Cat c2, IComparer<Cat> comparer) {...}
Protože IComparer je contravariant, tak do té soutěže můžu strčit AnimalWeightComparer a porovnávat kočky podle váhy. Sortu totiž můžu předat IComparer.