Arasındaki fark nedir <out T>
ve <T>
? Örneğin:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Arasındaki fark nedir <out T>
ve <T>
? Örneğin:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Yanıtlar:
out
Jenerik 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, in
karşı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 Bar
bir alt sınıfıdır Foo
, çünkü IComparer<in T>
arayüz kontravaryant .
Image
soyut 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 )
IList<object>
tuhaf bir örnektir, eğer isterseniz object
jeneriklere ihtiyacınız yoktur.
in
Ve out
anahtar 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
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 Banana
türüdürFruit
,
kabul eden fonksiyon ISkinned<Fruit>
sadece kabul edebilecektir ISkinned<Fruit>
.
" 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>
.
out
okuyana T
kadar sadece geri verilebilecek zorlamaların farkında değildim. Bütün konsept şimdi daha anlamlı!
Gönderdiğiniz bağlantıdan ....
Genel tür parametreleri için, out anahtar sözcüğü type parametresinin kovaryant olduğunu belirtir .
EDIT : Yine, gönderdiğiniz bağlantıdan
Daha fazla bilgi için, bkz. Kovaryans ve Çelişki (C # ve Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx