Я не был на PDC 2008, но услышал новости о том, что C # 4.0 объявлен для поддержки универсальной ковариантности и контр-дисперсии. То есть List<string>
можно назначить List<object>
. Как такое могло быть?
В книге Джона Скита « C # in Depth» объясняется, почему универсальные шаблоны C # не поддерживают ковариацию и контр-дисперсию. Это в основном для написания безопасного кода. Теперь C # 4.0 изменился для их поддержки. Принесет ли это хаос?
Кто-нибудь знает подробности о С # 4.0, может дать какое-то объяснение?
c#
c#-4.0
covariance
contravariance
generic-variance
Морган Ченг
источник
источник
Ответы:
Вариативность будет поддерживаться только безопасным способом - фактически, с использованием уже имеющихся у CLR возможностей. Так что примеры, которые я привожу в книге, попытки использовать a
List<Banana>
какList<Fruit>
(или что бы там ни было) все равно не сработают, но несколько других сценариев будут.Во-первых, он будет поддерживаться только для интерфейсов и делегатов.
Во-вторых, он требует, чтобы автор интерфейса / делегата украсил параметры типа как
in
(для контравариантности) илиout
(для ковариации). Самый очевидный пример - это то,IEnumerable<T>
что позволяет вам только «извлекать» из него значения - он не позволяет вам добавлять новые. Что станетIEnumerable<out T>
. Это нисколько не вредит безопасности типов, но позволяет, например, возвращатьIEnumerable<string>
из метода, объявленного для возвратаIEnumerable<object>
.Контравариантность сложнее привести конкретные примеры использования интерфейсов, но с делегатом это легко. Учтите
Action<T>
- это просто представляет метод, который принимаетT
параметр. Было бы неплохо иметь возможность беспрепятственно конвертировать, используяAction<object>
как anAction<string>
- любой метод, который принимаетobject
параметр, будет прекрасен, еслиstring
вместо этого он будет представлен с . Конечно, в C # 2 уже есть ковариация и контравариантность делегатов в некоторой степени, но через фактическое преобразование из одного типа делегата в другой (создание нового экземпляра) - см. P141-144 для примеров. C # 4 сделает это более универсальным и (я полагаю) позволит избежать создания нового экземпляра для преобразования. (Вместо этого это будет ссылочное преобразование.)Надеюсь, это немного проясняет ситуацию - пожалуйста, дайте мне знать, если это не имеет смысла!
источник
List<Banana>
какIList<Fruit>
» , как @ Арк-кун сказал? Если да, то как это возможно, хотя параметр типаIList<T>
интерфейса не определен как ковариантный (нетout T
, а простоT
).Не то чтобы Джон еще не рассказал об этом, но вот несколько ссылок на блоги и видео Эрика Липперта. Он прекрасно объясняет это на примерах.
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
источник