Страницы

Поиск по вопросам

суббота, 13 октября 2018 г.

Почему в C# классы не поддерживают ковариантность и контрвариантность?

Почему только интерфейсы и делегаты в C# поддерживают технику ковариантности и контрвариантности в Generic типах?


Ответ

Хороший вопрос.
Простой, поверхностный ответ — потому что это до сих пор не было имплементировано в языке. Но возникает вопрос, почему это не было имплементировано? Смотрите.
Дел в том, что C# появился как чисто императивный язык, в котором основной тип структур данных — мутабельные (то есть, изменяемые) структуры данных. Теперь представьте себе, что у вас есть класс C. Что вы будете делать с типом T?
Вы не можете иметь метод с входным параметром типа T. Потому что вследствие out у вас может в качестве входного параметра реально прийти тип, базовый для T (по смыслу контравариантности, поэтому-то и используется ключевое слово out: T может встречаться только в «исходящих» позициях, в качестве возвращаемого значения).
То же относится и к публичным свойствам типа T с сеттером (и полям), т. к. это по сути та же функция, принимающая на вход T
Вы не сможете иметь полезное приватное мутабельное поле типа T. Почему? Подумайте, как вы присвоите ему какое-нибудь новое значение. Откуда вы его возьмёте? У вас нету методов, которые принимают на вход T, по описанным причинам, вы можете лишь самостоятельно сконструировать экземпляр. Так что ваше поле типа T будет скорее всего бесполезно.
Без мутабельных полей типа T, много ли будет пользы от такого параметра? Вот поэтому разработчики языка и решили не заморачиваться с поддержкой контравариантности для классов. С ковариантностью по сути та же история, только вместо невозможности записи в поле типа T вы столкнётесь с невозможностью чтения из него: ко- и контравариантность симметричны.

Сейчас язык C# развивается в сторону большей поддержки функционального стиля программирования, в котором популярны иммутабельные (неизменяемые) структуры данных. Если ваша структура данных иммутабельна, вы вполне можете сделать её контравариантной по параметру. Пример лучше всего посмотреть здесь (+T читать как out T). Поэтому стоит рассчитывать, что поддержку вариантности для классов добавят в следующих версиях языка.

Идеи ответа одолжены из ответа Эрика Липперта, разработчика ко- и контравариантности в C#.

Комментариев нет:

Отправить комментарий