Как реализована общая ковариантность и контрастность в 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

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

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

Другие вопросы по тегам