Как универсальная ковариация и контравариантность реализованы в C # 4.0?

Я не был на PDC 2008, но услышал новости о том, что C # 4.0 объявлен для поддержки универсальной ковариантности и контр-дисперсии. То есть List<string> можно назначить List<object>. Как такое могло быть?

В книге Джона Скита C # in Depth объясняется, почему универсальные шаблоны C # не поддерживают ковариацию и контр-дисперсию. Это в основном для написания безопасного кода. Теперь C # 4.0 изменился для их поддержки. Принесет ли это хаос?

Кто-нибудь знает подробности о С # 4.0, может дать какое-то объяснение?


person Morgan Cheng    schedule 29.10.2008    source источник
comment
Вот хорошая статья, которая описывает предстоящие реализации ковариации и контравариантности для делегатов и интерфейсов в C # 4.0: LINQ Farm: ковариация и контравариантность в C # 4.0   -  person Christian C. Salvadó    schedule 29.10.2008
comment
Андерс Норос объясняет в C # 4.0 - Ковариация и противоречие концепция и показывает, что она уже поддерживается сегодня в IL, начиная с .NET 2.0.   -  person Thomas Freudenberg    schedule 30.10.2008


Ответы (2)


Вариативность будет поддерживаться только безопасным способом - фактически, с использованием возможностей, которые уже есть в среде CLR. Так что примеры, которые я привожу в книге, попытки использовать List<Banana> как List<Fruit> (или что-то еще) по-прежнему не сработают, но несколько других сценариев будут.

Во-первых, он будет поддерживаться только для интерфейсов и делегатов.

Во-вторых, он требует, чтобы автор интерфейса / делегата украсил параметры типа как in (для контравариантности) или out (для ковариации). Самый очевидный пример - IEnumerable<T>, который позволяет вам извлекать только значения "вне" - он не позволяет вам добавлять новые. Это станет IEnumerable<out T>. Это нисколько не вредит безопасности типов, но позволяет, например, возвращать IEnumerable<string> из метода, объявленного для возврата IEnumerable<object>.

Контравариантность сложнее привести конкретные примеры использования интерфейсов, но с делегатом это легко. Рассмотрим Action<T> - это просто представляет метод, который принимает параметр T. Было бы неплохо иметь возможность беспрепятственно конвертировать, используя Action<object> как Action<string> - любой метод, который принимает параметр object, будет прекрасен, если вместо этого будет представлен string. Конечно, в C # 2 уже есть ковариация и контравариантность делегатов в некоторой степени, но через фактическое преобразование из одного типа делегата в другой (создание нового экземпляра) - см. P141-144 для примеров. C # 4 сделает это более универсальным и (я считаю) позволит избежать создания нового экземпляра для преобразования. (Вместо этого это будет ссылочное преобразование.)

Надеюсь, это немного проясняет ситуацию - пожалуйста, дайте мне знать, если это не имеет смысла!

person Jon Skeet    schedule 29.10.2008
comment
Итак, означает ли это, что если класс объявлен как List ‹out T›, тогда он НЕ должен иметь функцию-член, такую ​​как void Add (T obj)? Компилятор C # 4.0 сообщит об ошибке, верно? - person Morgan Cheng; 30.10.2008
comment
Морган: Я так понимаю, да. - person Jon Skeet; 31.10.2008
comment
И снова один из ваших ответов здесь на SO немедленно помог мне улучшить некоторый код. Спасибо! - person Mark; 08.10.2010
comment
@ Арк-кун: Да, я в курсе. Следовательно, все еще не будет работать в том же предложении. (И причины мне тоже известны.) - person Jon Skeet; 09.06.2013
comment
@JonSkeet Правильно ли, что вы можете использовать только List<Banana> в качестве IList<Fruit>, как сказал @ Ark-kun? Если да, то как это возможно, хотя параметр типа _ 3_ интерфейс не определяется как ковариантный (не out T, а просто T). - person gehho; 23.10.2013
comment
@gehho: Нет, вы не можете - но вы можете использовать его как IEnumerable<Fruit>. Я удивлен, что не уловил этого, когда был написан комментарий ... - person Jon Skeet; 23.10.2013
comment
@JonSkeet Хорошо, понял. Был счастлив, что наконец понял общую тему ковариантности, а потом увидел вот это ... :) Спасибо за быстрый ответ! - person gehho; 23.10.2013
comment
@gehho Итак, в моем комментарии была еще одна ошибка ... Удален комментарий, чтобы избежать путаницы в будущем. - person Ark-kun; 23.10.2013

Не то чтобы Джон еще не рассказал об этом, но вот несколько ссылок на блоги и видео Эрика Липперта. Он прекрасно объясняет это на примерах.

https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and-contravariance-in-c-part-one/

Видео:

https://www.youtube.com/watch?v=3MQDrKbzvqU

https://www.youtube.com/watch?v=XRIadQaBYlI

https://www.youtube.com/watch?v=St9d2EDZfrg

person kemiller2002    schedule 16.04.2010