Коваріація і контраваріація в універсальних шаблонах

Терміни "коваріантність" і "контраваріантних" відносяться до можливості використовувати тип меншою або більшою глибини спадкування, ніж заданий спочатку. Параметри універсальних типів підтримують коваріантність і контраваріантних і забезпечують більшу гнучкість у призначенні та використанні універсальних типів. Нижче наведені визначення термінів "коваріантність", "контраваріантних" і "інваріантність" в контексті системи типів. У цьому прикладі передбачається наявність базового класу з ім'ям Base і похідного класу з ім'ям Derived.

Дозволяє використовувати тип кольорів із більшою кількістю спадкування, ніж задано спочатку.

примірник IEnumerable (IEnumerable (Of Derived) в Visual Basic) можна привласнити змінної типу IEnumerable.

Дозволяє використовувати більш універсальний тип (з меншою глибиною спадкування), ніж заданий спочатку.

примірник IEnumerable (IEnumerable (Of Base) в Visual Basic) можна привласнити змінної типу IEnumerable.

Чи означає, що можна використовувати тільки спочатку заданий тип. Таким чином, параметр інваріантного універсального типу не є ні коваріантним, ні контраваріантним.

примірник IEnumerable (IEnumerable (Of Base) в Visual Basic) не можна привласнити змінної типу IEnumerable. і навпаки.

Параметри коваріантного типу дозволяють створювати призначення, які виглядають дуже схоже на звичайний Поліморфізм (Керівництво з програмування на C #). як показує наступний код.

Це може здатися кроком назад, але це тіпобезопасний код, який компілюється і виконується. Лямбда-вираз відповідає делегату, якому присвоєно, і визначає метод, який приймає один параметр типу Base і не має значення, що повертається. Результуючий делегат може бути присвоєно змінній типу Action. так як параметр типу T делегата Action є контраваріантним. Код є тіпобезопасним, тому що T задає тип параметра. Коли делегат типу Action викликаний так, як якщо б він був делегатом типу Action. його аргумент повинен бути аргументом типу Derived. Цей аргумент завжди може бути безпечно переданий базового методу, тому що параметр методу є параметром типу Base.

У загальному випадку, параметр коваріантного типу може бути використаний в якості повертається типу делегата, і параметри контраваріантного типу можуть бути використані в якості типів параметра. Для інтерфейсу параметри коваріантного типу можуть бути використані в якості повертаються типів методів інтерфейсу, і параметри контраваріантного типу можуть бути використані як типи параметра методів інтерфейсу.

Разом коваріантність і контрваріантность називаються варіацією. Параметр універсального типу, який не зазначений як коваріантний або контраваріантний, називається інваріантним. Короткі відомості про варіативності в загальномовна середовищі виконання:

В .NET Framework 4 наступні інтерфейси і типи делегатів мають коваріантні і / або контраваріантниє параметри типу.

Тип універсального інтерфейсу або універсального методу-делегата може мати як коваріантні, так і контраваріантниє параметри типу.

Варіативність застосовується тільки до посилальним типам; якщо вказати тип значення для параметра вариантного типу, цей параметр типу єінваріантні для типу, створеного в результаті.

А ось варіативність не може бути застосована до об'єднання делегатів. Тому для заданих двох делегатів типів Action і Action (Action (Of Derived) і Action (Of Base) в Visual Basic) не можна об'єднувати перший делегат з другим, незважаючи на те що результат буде безпечним типом. А ось варіативність дозволяє присвоїти другий делегат змінної типу Action. але делегати можна об'єднувати, тільки якщо їх типи точно збігаються.

У наступних підрозділах детально описуються коваріантні і контрваріантние параметри типу.

В .NET Framework 4 наступні інтерфейси і типи делегатів мають коваріантні і / або контраваріантниє параметри типу. Ядро автоматизації UI маскує будь-які відмінності в структурах, що належать різним частинам UI. Це означає, що делегати можна привласнювати змінним, які мають більш похідні типи параметрів і (в разі універсальних методів-делегатів Func) менше похідні повертаються типи.

Останній параметр універсального типу універсальних методів-делегатів Func вказує тип значення в сигнатурі делегата. Він є коваріантним (ключове слово out), в той час як інші параметри універсального типу є контраваріантнимі (ключове слово in).

Це проілюстровано в наступному коді. Перша частина коду визначає клас з ім'ям Base. клас з ім'ям Derived. успадковує від класу Base. і ще один клас з методом типу static (Shared в Visual Basic) і ім'ям MyMethod. Цей метод приймає екземпляр класу Base і повертає екземпляр класу Derived. (Якщо аргумент є екземпляром класу Derived. Метод MyMethod повертає його, якщо аргумент є екземпляром класу Base. Метод MyMethod повертає новий екземпляр класу Derived.) У функції Main () приклад створюється екземпляр Func (Func (Of Base, Derived) в Visual Basic), що представляє метод MyMethod. і він зберігається в змінної f1.

Починаючи з платформи .NET Framework версії 2.0, середа CLR підтримує варіантні замітки для параметрів універсального типу. До версії .NET Framework 4 єдиним способом визначення універсального класу, що має такі замітки, було використання мови MSIL: або шляхом компіляції класу за допомогою програми Ilasm.exe (IL Assembler). або шляхом його введення в динамічну збірку.

Параметр коваріантного типу позначається ключовим словом out (ключовим словом Out в Visual Basic, ключовим словом + для асемблера MSIL Assembler). Параметр коваріантного типу можна використовувати як значення, що повертається методу, що належить інтерфейсу, або як повертається тип делегата. Параметр коваріантного типу не можна використовувати як обмеження універсального типу для методів інтерфейсу.

Якщо метод інтерфейсу має параметр з типом універсального методу-делегата, параметр коваріантного типу цього типу інтерфейсу може використовуватися для вказівки параметра контраваріантного типу цього типу делегата.

Параметр контраваріантного типу позначається ключовим словом in (ключовим словом In в Visual Basic, ключовим словом - для асемблера MSIL Assembler). Параметр контраваріантного типу можна використовувати як тип параметра методу, що належить інтерфейсу, або як тип параметра делегата. Параметр контраваріантного типу можна використовувати як обмеження універсального типу для методу інтерфейсу.

Параметри вариантного типу можуть мати тільки типи інтерфейсу і типи делегата. Тип інтерфейсу або тип делегата може мати як коваріантні, так і контраваріантниє параметри типу.

Мови Visual Basic і C # не дозволяють порушувати правила використання параметрів коваріантного і контраваріантного типів або додавати замітки ковариантности або контрваріантності в параметри типу, що мають тип, відмінний від інтерфейсів і делегатів. Ядро автоматизації UI маскує будь-які відмінності в структурах, що належать різним частинам UI.