<out T> vs <T> в Generics


189

У чому різниця між <out T>і <T>? Наприклад:

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

vs.

public interface IExample<T>
{
    ...
}

1
Хорошим прикладом можуть бути IObservable <T> і IObserver <T>, визначені в ns системи в mscorlib. публічний інтерфейс IObservable <out T> і публічний інтерфейс IObserver <in T>. Аналогічно, IEnumerator <out T>, IEnumerable <out T>
VivekDev

2
Найкраще пояснення, з яким я познайомився: agirlamonggeeks.com/2019/05/29/… . (<In T> <- означає, що T можна передавати лише як параметр методу; <out T> <- означає, що T може бути повернуто лише як результати методу)
Володимир Шарій

Відповіді:


212

outКлючове слово в відтворених використовується для позначення того, що тип Т в інтерфейсі коваріантен. Докладніше див. Коваріація та противаріантність .

Класичний приклад - це IEnumerable<out T>. Оскільки IEnumerable<out T>це коваріант, вам дозволяється робити наступне:

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

Другий рядок вище був би невдалим, якби це не було коваріантним, навіть якщо логічно воно повинно працювати, оскільки рядок походить від об'єкта. Перед тим, як до C # і VB.NET (у .NET 4 з VS 2010) додано відхилення в загальних інтерфейсах , це була помилка часу компіляції.

Після .NET 4, IEnumerable<T>був позначений коваріантом, і став IEnumerable<out T>. Оскільки IEnumerable<out T>використовує лише елементи всередині нього і ніколи не додає / не змінює їх, це безпечно трактувати численну колекцію рядків як численну колекцію об'єктів, що означає, що вона є коваріантною .

Це не працює з таким типом IList<T>, оскільки IList<T>має Addметод. Припустимо, це дозволить:

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

Ви можете зателефонувати:

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

Це, звичайно, не вдасться - тому IList<T>не можна позначати коваріант.

Також є, btw, варіант для in- який використовується такими речами, як інтерфейси порівняння. IComparer<in T>, наприклад, працює протилежно. Ви можете використовувати бетон IComparer<Foo>безпосередньо як підклас IComparer<Bar>if , оскільки інтерфейс є протилежним .BarFooIComparer<in T>


4
@ColeJohnson Тому Image, що це абстрактний клас;) Ви можете робити new List<object>() { Image.FromFile("test.jpg") };без проблем, а також можете new List<object>() { new Bitmap("test.jpg") };. Проблема з вашими полягає в тому, що new Image()це заборонено (ви теж не можете цього зробити var img = new Image();)
Reed Copsey

4
generic IList<object>- це химерний приклад, якщо ви хочете, objectщо вам не потрібні дженерики.
Джодрелл

5
@ReedCopsey Чи не суперечите ви власній відповіді у своєму коментарі?
MarioDS

64

Для легкого запам'ятовування використання inта outключових слів (також коваріації та протиріччя) ми можемо зобразити спадщину як обгортання:

String : Object
Bar : Foo

in out


11
Хіба це не так? Contravariance = in = дозволяє використовувати менш похідні типи замість більш похідних. / Covariance = out = дозволяє використовувати більше похідних типів замість менш похідних. Особисто, дивлячись на вашу діаграму, я читаю це як протилежне тому.
Сем Шилес

co u варіант (: для мене
снр

49

врахуйте,

class Fruit {}

class Banana : Fruit {}

interface ICovariantSkinned<out T> {}

interface ISkinned<T> {}

і функції,

void Peel(ISkinned<Fruit> skinned) { }

void Peel(ICovariantSkinned<Fruit> skinned) { }

Функція, яка приймає ICovariantSkinned<Fruit>, зможе прийняти ICovariantSkinned<Fruit>або ICovariantSkinned<Bananna>тому, що ICovariantSkinned<T>є коваріантним інтерфейсом і Bananaє типом Fruit,

функція, яка приймає ISkinned<Fruit>, зможе прийняти ISkinned<Fruit>.


38

" out T" означає, що тип T"коваріантний". Це обмежує Tвідображатись лише як повернене (вихідне) значення у методах загального класу, інтерфейсу чи методу. Це означає, що тип / інтерфейс / метод можна привласнити еквіваленту супер-типу T.
Напр. ICovariant<out Dog>Можна подати до ICovariant<Animal>.


14
Я не усвідомлював, що outправозастосування, які Tможна повернути, поки я не прочитав цю відповідь. Вся концепція має більше сенсу зараз!
MarioDS

6

З посилання, яке ви опублікували ....

Для загальних параметрів типу ключове слово out визначає, що параметр типу є коваріантним .

EDIT : Знову від посилання, яке ви опублікували

Для отримання додаткової інформації див. Коваріація та контраваріантність (C # та Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.