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:
outKluczowe 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 Addmetodę. 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 .BarFooIComparer<in T>
Imagejest 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 ini outsł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 Bananajest rodzajem Fruit,
funkcja, która akceptuje, ISkinned<Fruit>będzie mogła tylko zaakceptować ISkinned<Fruit>.
„ out T” oznacza, że typ Tjest „kowariantny”. Ogranicza Tto 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>.
outegzekwowania Tmoż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