У чому різниця між <out T>
і <T>
? Наприклад:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
У чому різниця між <out T>
і <T>
? Наприклад:
public interface IExample<out T>
{
...
}
vs.
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>
не можна позначати коваріант.
Також є, btw, варіант для 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
що вам не потрібні дженерики.
Для легкого запам'ятовування використання 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 визначає, що параметр типу є коваріантним .
EDIT : Знову від посилання, яке ви опублікували
Для отримання додаткової інформації див. Коваріація та контраваріантність (C # та Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx