В чем разница между <out T>
и <T>
? Например:
public interface IExample<out T>
{
...
}
против
public interface IExample<T>
{
...
}
c#
generics
covariance
Коул Джонсон
источник
источник
Ответы:
out
Ключевое слово в воспроизведенных используется для обозначения того, что тип Т в интерфейсе ковариантен. Смотрите Ковариантность и Контравариантность для деталей.Классический пример
IEnumerable<out T>
. ПосколькуIEnumerable<out T>
он ковариантен, вы можете делать следующее:Вторая строка выше потерпит неудачу, если это не будет ковариантно, хотя логически это должно работать, так как строка происходит от объекта. До того, как дисперсия универсальных интерфейсов была добавлена в C # и VB.NET (в .NET 4 с VS 2010), это была ошибка времени компиляции.
После .NET 4
IEnumerable<T>
был отмечен ковариант и сталIEnumerable<out T>
. Поскольку онIEnumerable<out T>
использует только элементы внутри него и никогда не добавляет / не изменяет их, для него безопасно обрабатывать перечисляемую коллекцию строк как перечислимую коллекцию объектов, что означает ее ковариантность .Это не будет работать с подобным типом
IList<T>
, так какIList<T>
имеетAdd
метод. Предположим, это будет разрешено:Вы могли бы тогда позвонить:
Это, конечно, потерпит неудачу - поэтому
IList<T>
не может быть отмечено ковариантным.Между прочим, существует также опция для
in
- которая используется такими вещами, как интерфейсы сравнения.IComparer<in T>
Например, работает наоборот. Вы можете использовать бетонIComparer<Foo>
непосредственно как подклассIComparer<Bar>
if , потому что интерфейс контравариантен .Bar
Foo
IComparer<in T>
источник
Image
что это абстрактный класс;) Вы можете делатьnew List<object>() { Image.FromFile("test.jpg") };
без проблем, или вы можете делать тоnew List<object>() { new Bitmap("test.jpg") };
же самое . Проблема с твоим заключается в том, чтоnew Image()
это не разрешено (ты тоже не можешь этого сделатьvar img = new Image();
)IList<object>
- причудливый пример, если вы хотитеobject
s, вам не нужны дженерики.Для удобства запоминания использования
in
иout
ключевого слова (а также ковариации и контравариантности) мы можем использовать наследование изображения в виде переноса:источник
рассматривать,
и функции,
Функция, которая принимает,
ICovariantSkinned<Fruit>
будет в состоянии принятьICovariantSkinned<Fruit>
илиICovariantSkinned<Bananna>
потому чтоICovariantSkinned<T>
является ковариантным интерфейсом иBanana
типомFruit
,функция, которая принимает,
ISkinned<Fruit>
сможет только принятьISkinned<Fruit>
.источник
«
out T
» означает, что типT
является «ковариантным». Это ограничиваетT
отображение только как возвращенное (исходящее) значение в методах универсального класса, интерфейса или метода. Подразумевается, что вы можете привести тип / интерфейс / метод к эквиваленту с супер-типомT
.Например,
ICovariant<out Dog>
можно привести кICovariant<Animal>
.источник
out
принудительные меры, которыеT
могут быть возвращены только, пока я не прочитал этот ответ. Вся концепция имеет больше смысла сейчас!По ссылке вы разместили ....
РЕДАКТИРОВАТЬ : опять же по ссылке, которую вы разместили
источник