Jaka jest różnica między <out T>
i <T>
? Na przykład:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Jaka jest różnica między <out T>
i <T>
? Na przykład:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Odpowiedzi:
out
Kluczowe w generycznych jest używana do określenia, że typ T w interfejsie jest kowariantna. Zobacz Kowariancja i kontrawariancja, aby uzyskać szczegółowe informacje.
Klasycznym przykładem jest IEnumerable<out T>
. Ponieważ IEnumerable<out T>
jest to kowariant, możesz wykonać następujące czynności:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
Druga linia powyżej nie powiodłaby się, gdyby nie była to zmienna kowariantna, chociaż logicznie powinna działać, ponieważ łańcuch pochodzi od obiektu. Przed dodaniem wariancji w ogólnych interfejsach do C # i VB.NET (w .NET 4 z VS 2010) był to błąd czasu kompilacji.
Po .NET 4 IEnumerable<T>
został oznaczony jako kowariant i stał się IEnumerable<out T>
. Ponieważ IEnumerable<out T>
używa tylko zawartych w nim elementów i nigdy ich nie dodaje / nie zmienia, można bezpiecznie traktować wymienną kolekcję ciągów jako wymienną kolekcję obiektów, co oznacza, że jest ona kowariantna .
Nie działałoby to z typem podobnym IList<T>
, ponieważ IList<T>
ma Add
metodę. Załóżmy, że byłoby to dozwolone:
IList<string> strings = new List<string>();
IList<object> objects = strings; // NOTE: Fails at compile time
Możesz wtedy zadzwonić:
objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object
To by się oczywiście nie powiodło - więc IList<T>
nie można tego nazwać kowariantem.
Istnieje również opcja dla in
- która jest używana przez takie rzeczy jak interfejsy porównawcze. IComparer<in T>
, na przykład działa odwrotnie. Betonu można użyć IComparer<Foo>
bezpośrednio jako podklasy IComparer<Bar>
if , ponieważ interfejs jest sprzeczny .Bar
Foo
IComparer<in T>
Image
jest to klasa abstrakcyjna;) Możesz zrobić to new List<object>() { Image.FromFile("test.jpg") };
bez problemów lub możesz zrobić to new List<object>() { new Bitmap("test.jpg") };
samo. Problem z twoim jest taki, że new Image()
nie jest dozwolony (ty też nie możesz tego zrobić var img = new Image();
)
IList<object>
to dziwny przykład, jeśli chcesz object
, nie potrzebujesz ogólnych .
Aby łatwo zapamiętać użycie in
i out
słowa kluczowego (również kowariancji i kontrawariancji), możemy obrazować dziedziczenie jako opakowanie:
String : Object
Bar : Foo
rozważać,
class Fruit {}
class Banana : Fruit {}
interface ICovariantSkinned<out T> {}
interface ISkinned<T> {}
i funkcje,
void Peel(ISkinned<Fruit> skinned) { }
void Peel(ICovariantSkinned<Fruit> skinned) { }
Funkcja, która akceptuje, ICovariantSkinned<Fruit>
będzie w stanie ją zaakceptować ICovariantSkinned<Fruit>
lub ICovariantSkinned<Bananna>
ponieważ ICovariantSkinned<T>
jest interfejsem kowariantnym i Banana
jest rodzajem Fruit
,
funkcja, która akceptuje, ISkinned<Fruit>
będzie mogła tylko zaakceptować ISkinned<Fruit>
.
„ out T
” oznacza, że typ T
jest „kowariantny”. Ogranicza T
to wyświetlanie tylko jako wartość zwracaną (wychodzącą) w metodach ogólnej klasy, interfejsu lub metody. Implikacją jest to, że można rzutować typ / interfejs / metodę na odpowiednik z supertypem T
.
Np. ICovariant<out Dog>
Można rzucić na ICovariant<Animal>
.
out
egzekwowania T
można zwrócić tylko, dopóki nie przeczytam tej odpowiedzi. Cała koncepcja ma teraz większy sens!
Z opublikowanego linku ....
W przypadku ogólnych parametrów typu słowo kluczowe out określa, że parametr typu jest kowariantny .
EDYCJA : Znowu z linku, który opublikowałeś
Aby uzyskać więcej informacji, zobacz Kowariancja i kontrawariancja (C # i Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx