Polja u .NET-u označavana su kao kovarijantna. Isto tako pojavom Generics-a u .NET 2.0 svojstvo kovarijance i kontravarijane nije bilo podržano. U tom pogledu sljedeći kod u C# 3.0 ne može se kompajlirati:
Funkcija1<Student> studemt = () => new Student("Šemso", 1978, DateTime.Now); Funkcija1<Osoba> osoba = studemt; Akcija1<Osoba> osoba1 = (s) => { Print(s); }; Akcija1<Student> student1 = osoba1;
Bez obzira što je klasa Student izvedena iz klasa Osoba, ovakva konstrukcija koda nije validna. Upravo Varijanca kao novo proširenje C# 4.0 omogućuje nam konstrukciju koda kao u prethodnom primjeru, i sigurna provjeravanje izvedenih tipova. Jednostavno rečeno Varijanca je svojstvo operatora da se ponašaju kao tipovi. Iz tog razloga definisane su osobine KoVarijanca (Co-Variance) i KontraVarijanca (Contra-Varijance). Da bi prethodni primjer bilo kompajliran bez greške potrebno je Funkciju i Akciju implementirati u smuslu Kovarijantnosti odnosno KontraVarijantnosti.
Tj.
delegate T Funkcija1<out T>(); delegate void Akcija1<in T>(T a);
Deklaracija delegata Funkcija i Akcija imaju sličnu deklaraciju osim ključnih riječi in i out. Ovo znači da prvi delegat Funkcija služi samo za čitanje (read-only) i kao takav je type safe. U slučaju da hoćemo da naš delegat bude write –only odnoso KontraVarijantan tada koristimo ključnu riječ in, kao što je prikazano kod primjera delegata Akcija.
Čitav primjer korištenja Ko i Kontra Varijance dat je i narednom tekstu. Primjer je preuzet sa msdn i modificiran.
class Osoba { public Osoba() { } public Osoba(string ime, int id) { Ime = ime; ID = id; } public string Ime; public int ID; } class Student : Osoba { public Student() { } public Student(string ime, int id, DateTime upis) { Ime = ime; ID = id; datumUpisa = upis; } public DateTime datumUpisa; } class Program { //Da bi razumijeli nova proširenja CoVarijanca i KontraVarijanca pokušajte //kompajlirati program kada obrisete ključne riječi out i in sa deklaracije ova dva delegata delegate T Funkcija1<out T>(); delegate void Akcija1<in T>(T a); static void Main(string[] args) { Funkcija1<Student> student = () => new Student("Šemso", 1978, DateTime.Now); Funkcija1<Osoba> osoba = student; Funkcija1<Osoba> osoba2 = ()=> new Osoba("Mirso", 1555); Akcija1<Osoba> osoba1 = (s) => { Print(s); }; Akcija1<Student> student1 = osoba1; //Ispis objekta biće student jer je objekat osoba formiran iz studenta Print(osoba()); //Ispis objekta biće student student1(new Student("Emir", 1977, DateTime.Now.AddDays(-5))); //Ispis objekta Osoba Print(osoba2()); Console.Read(); } static void Print(Osoba p) { Student st = p as Student; if (st != null) Console.WriteLine("Student"); else Console.WriteLine("Osoba;"); Console.WriteLine("Name: {0};", p.Ime); Console.WriteLine("ID:{0}", p.ID); if (st != null) Console.WriteLine("Datum:{0}", st.datumUpisa); Console.WriteLine("_______________________________"); } }
Značajno je reći da Varijanca podržavana samo nad delegatima i interfejsima.