Как реализована общая ковариантность и контрастность в C# 4.0?
Я не посещал PDC 2008, но я слышал некоторые новости о том, что C# 4.0 объявлен для поддержки универсальной ковариации и контр-дисперсии. То есть, List<string>
может быть назначен List<object>
, Как это может быть?
В книге Джона Скита " C# in Depth" объясняется, почему дженерики C# не поддерживают ковариацию и контр-дисперсию. Это в основном для написания безопасного кода. Теперь C# 4.0 изменился, чтобы поддержать их. Принесет ли это хаос?
Кто-нибудь знает подробности о C# 4.0, может дать некоторые объяснения?
2 ответа
Дисперсия будет поддерживаться только безопасным способом - фактически с использованием способностей, которые уже есть у CLR. Так что примеры, которые я привожу в книге, пытаются использовать List<Banana>
как List<Fruit>
(или что бы то ни было) все еще не сработает - но несколько других сценариев сработают.
Во-первых, он будет поддерживаться только для интерфейсов и делегатов.
Во-вторых, он требует от автора интерфейса / делегата декорировать параметры типа как in
(для контравариантности) или out
(для ковариации). Самый очевидный пример IEnumerable<T>
который только позволяет вам извлекать из него значения - он не позволяет добавлять новые. Это станет IEnumerable<out T>
, Это не повредит безопасности типов, но позволяет вам вернуть IEnumerable<string>
из метода, объявленного для возврата IEnumerable<object>
например.
Contravariance труднее дать конкретные примеры использования интерфейсов, но это легко с делегатом. Рассматривать Action<T>
- это просто представляет метод, который принимает T
параметр. Было бы неплохо иметь возможность конвертировать без проблем использовать Action<object>
как Action<string>
- любой метод, который принимает object
Параметр будет хорошо, когда он представлен с string
вместо. Конечно, C# 2 уже имеет ковариацию и контравариантность делегатов в некоторой степени, но посредством фактического преобразования из одного типа делегата в другой (создание нового экземпляра) - см. P141-144 для примеров. C# 4 сделает это более общим, и (я полагаю) избежит создания нового экземпляра для преобразования. (Это будет ссылочное преобразование.)
Надеюсь, это немного прояснит ситуацию - пожалуйста, дайте мне знать, если это не имеет смысла!
Не то чтобы Джон еще не рассказал об этом, но вот несколько ссылок на блоги и видео от Эрика Липперта. Он хорошо объясняет это на примерах.
https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and-contravariance-in-c-part-one/
Видео:
https://www.youtube.com/watch?v=3MQDrKbzvqU