Generics'te <out T> vs <T>


189

Arasındaki fark nedir <out T>ve <T>? Örneğin:

public interface IExample<out T>
{
    ...
}

vs.

public interface IExample<T>
{
    ...
}

1
Buna iyi bir örnek, mscorlib'deki sistem ns'de tanımlanan IObservable <T> ve IObserver <T> olabilir. ortak arabirim IObservable <out T> ve genel arabirim IObserver <in T>. Benzer şekilde, IEnumerator <out T>, IEnumerable <out T>
VivekDev

2
Karşılaştığım en iyi açıklama: agirlamonggeeks.com/2019/05/29/… . (< İn T> <- T'nin yalnızca bir yönteme parametre olarak iletilebileceği anlamına gelir; <out T> <- T'nin sadece yöntem sonuçları olarak döndü)
Uladzimir Sharyi

Yanıtlar:


212

outJenerik anahtar arayüzü tipi T-bildirdiğinden olduğunu belirtmek için kullanılır. Ayrıntılar için Kovaryans ve karşıtlık konusuna bakın .

Klasik örnek IEnumerable<out T>. Yana IEnumerable<out T>bildirdiğinden olduğunu aşağıdakileri yapmanız izin konum:

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;

Yukarıdaki ikinci satır, eğer kovaryant değilse, mantıksal olarak çalışsa da, dize nesneden türediğinden başarısız olur. C # ve VB.NET'e (VS 2010 ile .NET 4'te) genel arabirimlerdeki varyans eklenmeden önce , bu bir derleme zamanı hatasıydı.

.NET 4'ten sonra IEnumerable<T>kovaryant olarak işaretlendi ve oldu IEnumerable<out T>. Yana IEnumerable<out T>sadece içindeki unsurları kullanır ve asla ekler / o 's gelir nesnelerinin numaralandırılabilir koleksiyonu, stringler enumerable koleksiyon tedavi etmek artık güvenli, onları değiştirir covariant .

Bir yöntemi IList<T>olduğundan, bu tür bir tür ile çalışmaz . Buna izin verileceğini varsayalım:IList<T>Add

IList<string> strings = new List<string>();
IList<object> objects = strings;  // NOTE: Fails at compile time

Daha sonra şunu arayabilirsiniz:

objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object

Bu elbette başarısız olur - bu nedenle IList<T>kovaryant olarak işaretlenemez.

Ayrıca, inkarşılaştırma arabirimleri gibi şeyler tarafından kullanılan - btw, için bir seçenek vardır . IComparer<in T>, örneğin, tam tersi şekilde çalışır. Bir beton kullanabilirsiniz IComparer<Foo>bir şekilde doğrudan IComparer<Bar>eğer Barbir alt sınıfıdır Foo, çünkü IComparer<in T>arayüz kontravaryant .


4
@ColeJohnson Çünkü Imagesoyut bir sınıf;) new List<object>() { Image.FromFile("test.jpg") };Hiçbir sorun olmadan yapabilirsiniz, ya da yapabilirsiniz new List<object>() { new Bitmap("test.jpg") };. Sizinki ile ilgili sorun new Image()izin verilmiyor (her var img = new Image();ikisini de yapamazsınız )
Reed Copsey

4
jenerik IList<object>tuhaf bir örnektir, eğer isterseniz objectjeneriklere ihtiyacınız yoktur.
Jodrell

5
@ReedCopsey Yorumunuzda kendi cevabınızla çelişmiyor musunuz?
MarioDS

64

inVe outanahtar kelimelerinin (aynı zamanda kovaryans ve kontravaryans) kullanımını kolayca hatırlamak için , kalıtımı sarma olarak görüntüleyebiliriz:

String : Object
Bar : Foo

giriş / çıkış


11
Bu yanlış bir yol değil mi? Contravariance = in = daha türetilmiş yerine daha az türetilmiş tiplerin kullanılmasına izin verir. / Covariance = out = daha az türetilen yerine daha fazla türetilen tipin kullanılmasına izin verir. Şahsen, diyagramınıza bakarak, bunun tersi olarak okudum.
Sam Shiles

co u varyant (: benim için
snr

49

düşünmek,

class Fruit {}

class Banana : Fruit {}

interface ICovariantSkinned<out T> {}

interface ISkinned<T> {}

ve fonksiyonlar,

void Peel(ISkinned<Fruit> skinned) { }

void Peel(ICovariantSkinned<Fruit> skinned) { }

Kabul işlevi ICovariantSkinned<Fruit>kabul etmek mümkün olacak ICovariantSkinned<Fruit>ya da ICovariantSkinned<Bananna>çünkü ICovariantSkinned<T>bir kovaryant arayüzüdür ve BananatürüdürFruit ,

kabul eden fonksiyon ISkinned<Fruit>sadece kabul edebilecektir ISkinned<Fruit>.


38

" out T", bu türün T"kovaryant" olduğunu belirtir . Bu T, genel sınıf, arabirim veya yöntemin yöntemlerinde yalnızca döndürülen (giden) bir değer olarak görünmeyi kısıtlar . Bunun anlamı, type / interface / yöntemini, süper türdeki bir eşdeğere yayınlayabilmenizdir T.
Örneğin ICovariant<out Dog>için dökme olabilir ICovariant<Animal>.


14
Bu cevabı outokuyana Tkadar sadece geri verilebilecek zorlamaların farkında değildim. Bütün konsept şimdi daha anlamlı!
MarioDS

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.