В чем разница между <out T>
и <T>
? Например:
public interface IExample<out T>
{
...
}
против
public interface IExample<T>
{
...
}
В чем разница между <out T>
и <T>
? Например:
public interface IExample<out T>
{
...
}
против
public interface IExample<T>
{
...
}
Ответы:
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>
не может быть отмечено ковариантным.
Между прочим, существует также опция для 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
ключевого слова (а также ковариации и контравариантности) мы можем использовать наследование изображения в виде переноса:
String : Object
Bar : Foo
рассматривать,
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>
.
« out T
» означает, что тип T
является «ковариантным». Это ограничивает T
отображение только как возвращенное (исходящее) значение в методах универсального класса, интерфейса или метода. Подразумевается, что вы можете привести тип / интерфейс / метод к эквиваленту с супер-типом T
.
Например, ICovariant<out Dog>
можно привести к ICovariant<Animal>
.
out
принудительные меры, которые T
могут быть возвращены только, пока я не прочитал этот ответ. Вся концепция имеет больше смысла сейчас!
По ссылке вы разместили ....
Для параметров универсального типа ключевое слово out указывает, что параметр типа ковариантен .
РЕДАКТИРОВАТЬ : опять же по ссылке, которую вы разместили
Для получения дополнительной информации см. Ковариантность и Контравариантность (C # и Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx