Ковариантность и контравариантность (программирование): различия между версиями

[отпатрулированная версия][отпатрулированная версия]
Содержимое удалено Содержимое добавлено
Строка 51:
 
=== C# ===
В языке [[C Sharp|C#]], начиная с первой его версии, массивы ковариантны. Это было сделано для совместимости с языком Java<ref>{{cite web|url=http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx|title=Covariance and Contravariance in C#, Part Two|author=Eric Lippert|date=2007-10-17|accessdate=2013-06-22}}</ref>. ТакПри же,попытке как изаписать в Джаве,массив контейнеры,элемент начинаяневерного стипа версиивыбрасывается 2.0,[[Обработка когдаисключений|исключение]] появилисьво обобщённыевремя типы,выполнения. были инвариантными.
{{редактирую раздел|1=[[Служебная:Contributions/Yms|Yms]]|2=10:19, 22 июня 2013 (UTC)}}
В языке [[C Sharp|C#]], начиная с первой его версии, массивы ковариантны. Это было сделано для совместимости с языком Java<ref>{{cite web|url=http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx|title=Covariance and Contravariance in C#, Part Two|author=Eric Lippert|date=2007-10-17|accessdate=2013-06-22}}</ref>. Так же, как и в Джаве, контейнеры, начиная с версии 2.0, когда появились обобщённые типы, были инвариантными.
 
Обобщённые классы и интерфейсы, появившиеся в C# 2.0, стали, как и в Джаве, инвариантными по типу-параметру.
Делегаты, которые начиная с C# 2.0 тоже могут быть обобщёнными (параметризированными по типам их аргументов и возвращаемым типам), в этой версии языка стали позволять автоматическое преобразование обычных методов к обобщённым делегатам с ковариантностью по возвращаемым типам и контравариантностью по типам аргументов. Поэтому в C# 2.0 стал возможен код следующего вида:
 
Делегаты,С которыевведением начинаяобобщённых с C# 2.0 тоже могут быть обобщённымиделегатов (параметризированнымипараметризированных по типам их аргументов и возвращаемым типам), в этой версии языка сталиязык позволятьпозволил автоматическое преобразование обычных методов к обобщённым делегатам с ковариантностью по возвращаемым типам и контравариантностью по типам аргументов. Поэтому в C# 2.0 стал возможен код следующего вида:
<source lang="csharp">
class Cat : Animal {}
Строка 64 ⟶ 65 :
Action<String> process = ProcessAnyObject;
process(myString); // легальное действие
 
Func<Object> getter = GetString();
Object obj = getter(); // легальное действие
</source>
однако код <code>Action<Object> process = ProcessString;</code> некорректен и даёт ошибку компиляции, иначе этот делегат можно было бы потом вызвать как <code>process(Int325)</code>, передавая Int32 в ProcessString.
 
В C# 2.0 и 3.0 этот механизм позволял лишь записывать простые методы в обобщённые делегаты и не мог делать автоматическое преобразование одних обобщённых делегатов в другие. Иначе говоря, код
Строка 75 ⟶ 77 :
</source>
в этих версиях языка не компилировался. Таким образом, обобщённые делегаты в C# 2.0 и 3.0 всё ещё были инвариантными.
 
<!--Начиная с C# 4.0, в язык стало возможным явно задавать ко- и контравариантность параметров обобщённых типов. Для этого используются ключевые слова in и out.-->
В C# 4.0 это ограничение было снято, и начиная с этой версии код <code>f2 = f1</code> в примере выше стал работать.
 
Кроме того, в 4.0 стало возможным задавать вариантность параметров обобщённых интерфейсов и делегатов явным образом. Для этого используются ключевые слова <code>out</code> и <code>in</code> соответственно. Поскольку в обобщённом типе реальное использование типа-параметра известно лишь его автору, к тому же оно может меняться в процессе разработки, это решение обеспечивает наибольшую гибкость без ущерба для надёжности контроля типов.
 
Некоторые библиотечные интерфейсы и делегаты были переопределены в C# 4.0 с использованием этих возможностей. Например, интерфейс <code>IEnumerable<T></code> отныне стал определяться как <code>IEnumerable<out T></code>, интерфейс <code>IComparable<T></code> — как <code>IComparable<in T></code>, делегат <code>Action<T></code> — как <code>Action<in T></code>, и т. п.
 
== Примечания ==