Различие будет только поддерживаться в безопасный путь - на самом деле, с помощью способностей, которые уже имеет 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 сделает это более универсальное, и (я верю), постарается не создавать новый экземпляр для преобразования. (Это будет ссылочное преобразование вместо этого.)
Hope это разрешает, это немного - сообщило мне, не имеет ли это смысла!
Не то чтобы Джон уже рассказывал об этом, но вот несколько ссылок на блоги и видео от Эрика Липперта. Он хорошо объясняет это на примерах.
https://blogs.msdn.microsoft.com/ericlippert/2007/10/16/covariance-and-contravariance-in-c-part-one/
Видео:
https://www.youtube.com/watch?v=3MQDrKbzvqU