В чем разница между <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
в generics используется для обозначения того, что тип T в интерфейсе ковариантен. Подробнее см. Ковариация и контравариантность.
Классический пример IEnumerable<out T>
. Поскольку IEnumerable<out T>
является ковариантным, вы можете сделать следующее:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
Вторая строка выше завершится неудачно, если это не будет ковариантным, хотя логически это должно работать, поскольку строка происходит от объекта. До дисперсия в общих интерфейсах была добавлена в С# и 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>
, если Bar
является подклассом Foo
, потому что интерфейс IComparer<in T>
контравариантен.
Чтобы легко запомнить использование ключевых слов 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
отображаться только как возвращаемое (исходящее) значение в методах общего класса, интерфейса или метода. Подразумевается, что вы можете применить метод type/interface/method к эквиваленту с супертипом T
.
Например. ICovariant<out Dog>
может быть добавлено к ICovariant<Animal>
.
Из опубликованной вами ссылки....
Для параметров типового типа ключевое слово out указывает, что тип параметр является ковариантным.
ИЗМЕНИТЬ: Опять же, из ссылки, которую вы разместили
Дополнительные сведения см. в разделе Ковариация и контравариантность (С# и Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx