İşte bir miras hiyerarşisi kullanan basit bir örnek.
Basit sınıf hiyerarşisi göz önüne alındığında:

Ve kodda:
public abstract class LifeForm { }
public abstract class Animal : LifeForm { }
public class Giraffe : Animal { }
public class Zebra : Animal { }
Değişmezlik (yani, genel tip parametreleri * ile süslenmemiş *in veya outanahtar kelimeler)
Görünüşe göre, böyle bir yöntem
public static void PrintLifeForms(IList<LifeForm> lifeForms)
{
foreach (var lifeForm in lifeForms)
{
Console.WriteLine(lifeForm.GetType().ToString());
}
}
... heterojen bir koleksiyonu kabul etmelidir:
var myAnimals = new List<LifeForm>
{
new Giraffe(),
new Zebra()
};
PrintLifeForms(myAnimals); // Giraffe, Zebra
Ancak, daha türetilmiş tipte bir koleksiyonu geçmek başarısız olur!
var myGiraffes = new List<Giraffe>
{
new Giraffe(), // "Jerry"
new Giraffe() // "Melman"
};
PrintLifeForms(myGiraffes); // Compile Error!
cannot convert from 'System.Collections.Generic.List<Giraffe>' to 'System.Collections.Generic.IList<LifeForm>'
Neden? Genel parametre IList<LifeForm>kovaryant olmadığından -
IList<T>değişmez olduğundan, IList<LifeForm>yalnızca parametrelenen türün Tolması gereken koleksiyonları (IList uygulayan) kabul ederLifeForm .
Yöntemin uygulanması PrintLifeFormskötü amaçlıysa (ancak aynı yöntem imzasına sahipse), derleyicinin geçişini engellemesinin nedeni List<Giraffe>açıktır:
public static void PrintLifeForms(IList<LifeForm> lifeForms)
{
lifeForms.Add(new Zebra());
}
Yana IListizin ekleme ya da elemanların çıkarılması, herhangi bir alt-sınıfı LifeForm, böylece bir parametre ilave edilebilir lifeForms, ve elde edilen tiplerinin herhangi toplama tipi ihlal edeceği yönteme geçirildi. (Burada, kötü niyetli yöntem eklemek girişiminde ZebraTo var myGiraffes). Neyse ki, derleyici bizi bu tehlikeden korur.
Kovaryans (Parametrik tip süslemeli genel out)
Kovaryans, değişmez koleksiyonlarla yaygın olarak kullanılır (yani bir koleksiyona yeni elemanların eklenemediği veya koleksiyondan çıkarılamadığı durumlarda)
Yukarıdaki örneğin çözümü, bir kovaryant jenerik toplama tipinin kullanılmasını sağlamaktır, örn. IEnumerable(Olarak tanımlanmıştır IEnumerable<out T>). IEnumerablekoleksiyona geçmek için herhangi bir yöntem yoktur ve outkovaryansın bir sonucu olarak, alt tipine sahip herhangi bir koleksiyon LifeFormartık yönteme geçirilebilir:
public static void PrintLifeForms(IEnumerable<LifeForm> lifeForms)
{
foreach (var lifeForm in lifeForms)
{
Console.WriteLine(lifeForm.GetType().ToString());
}
}
PrintLifeFormsŞimdi ile çağrılabilir Zebras, Giraffesve herhangi IEnumerable<>herhangi alt sınıfınınLifeForm
Çelişki (Parametrik tip süslemeli genel in)
İşlevler parametre olarak iletildiğinde karşıtlık sıklıkla kullanılır.
Aşağıda Action<Zebra>parametre olarak alan ve bilinen bir Zebra örneğinde çağıran bir işlev örneği verilmiştir:
public void PerformZebraAction(Action<Zebra> zebraAction)
{
var zebra = new Zebra();
zebraAction(zebra);
}
Beklendiği gibi, bu iyi çalışıyor:
var myAction = new Action<Zebra>(z => Console.WriteLine("I'm a zebra"));
PerformZebraAction(myAction); // I'm a zebra
Sezgisel olarak, bu başarısız olacaktır:
var myAction = new Action<Giraffe>(g => Console.WriteLine("I'm a giraffe"));
PerformZebraAction(myAction);
cannot convert from 'System.Action<Giraffe>' to 'System.Action<Zebra>'
Ancak, bu başarılı
var myAction = new Action<Animal>(a => Console.WriteLine("I'm an animal"));
PerformZebraAction(myAction); // I'm an animal
ve bu da başarılı olur:
var myAction = new Action<object>(a => Console.WriteLine("I'm an amoeba"));
PerformZebraAction(myAction); // I'm an amoeba
Neden? Çünkü Actionolarak tanımlanır Action<in T>, yani bunun contravariantiçin, yani, Action<Zebra> myActionbu, myAction"en", bir de olabilir Action<Zebra>ki, ama daha az türetilmiş süper sınıf Zebrada kabul edilebilir.
Bu başlangıçta sezgisel olmasa da (örneğin Action<object>, bir parametre gerektiren nasıl geçirilebilir Action<Zebra>?), Adımları kaldırırsanız, çağrılan fonksiyonun ( PerformZebraAction) kendisinin veri geçirmekten sorumlu olduğunu (bu örnekte bir Zebraörnek ) göreceksiniz. ) işleve - veriler arama kodundan gelmez.
Daha yüksek dereceli işlevleri bu şekilde kullanma tersine çevrilmiş yaklaşımı nedeniyle Action, çağrıldığında, işlevin kendisi daha az türetilmiş bir tür kullanmasına rağmen, işleve (parametre olarak iletilir) Zebraçağrılan daha türetilmiş örnektir zebraAction.