Jaka jest różnica między <out T>
i <T>
? Na przykład:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
c#
generics
covariance
Cole Johnson
źródło
źródło
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: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>
maAdd
metodę. Załóżmy, że byłoby to dozwolone:Możesz wtedy zadzwonić:
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 podklasyIComparer<Bar>
if , ponieważ interfejs jest sprzeczny .Bar
Foo
IComparer<in T>
źródło
Image
jest to klasa abstrakcyjna;) Możesz zrobić tonew List<object>() { Image.FromFile("test.jpg") };
bez problemów lub możesz zrobić tonew List<object>() { new Bitmap("test.jpg") };
samo. Problem z twoim jest taki, żenew Image()
nie jest dozwolony (ty też nie możesz tego zrobićvar img = new Image();
)IList<object>
to dziwny przykład, jeśli chceszobject
, nie potrzebujesz ogólnych .Aby łatwo zapamiętać użycie
in
iout
słowa kluczowego (również kowariancji i kontrawariancji), możemy obrazować dziedziczenie jako opakowanie:źródło
rozważać,
i funkcje,
Funkcja, która akceptuje,
ICovariantSkinned<Fruit>
będzie w stanie ją zaakceptowaćICovariantSkinned<Fruit>
lubICovariantSkinned<Bananna>
ponieważICovariantSkinned<T>
jest interfejsem kowariantnym iBanana
jest rodzajemFruit
,funkcja, która akceptuje,
ISkinned<Fruit>
będzie mogła tylko zaakceptowaćISkinned<Fruit>
.źródło
„
out T
” oznacza, że typT
jest „kowariantny”. OgraniczaT
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 supertypemT
.Np.
ICovariant<out Dog>
Można rzucić naICovariant<Animal>
.źródło
out
egzekwowaniaT
można zwrócić tylko, dopóki nie przeczytam tej odpowiedzi. Cała koncepcja ma teraz większy sens!Z opublikowanego linku ....
EDYCJA : Znowu z linku, który opublikowałeś
źródło