TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #31 1.19K
День двадцать третий. #ЗаметкиНаПолях
Ковариантность и Контравариантность в Обобщениях (начало)

Очень обширная тема, поэтому разобью её на четыре поста:
1. Общие понятия
2. Вариантность в обобщённых интерфейсах
3. Вариантность в обобщённых делегатах
4. Определение вариантных интерфейсов и делегатов

1. Общие понятия
Ковариантность и контравариантность относятся к возможности использования более конкретного (производного) типа или более общего (базового) типа, чем изначально обозначенный. Обобщённые параметры типа поддерживают ковариантность и конртавариантность, чтобы предоставлять большую гибкость в присвоении и использовании обобщённых типов. В следующих примерах допустим, что Animal – базовый класс, а Cat – производный от него.

Инвариантность означает, что вы можете использовать только изначально определённый тип.

Ковариантность позволяет вам использовать производный (более конкретный) тип, чем изначально обозначенный. Вы можете присвоить экземпляр IEnumerable<Cat> переменной типа IEnumerable<Animal>.
Ковариантные параметры типа позволяют вам делать присваивания, похожие на обычный полиморфизм:
IEnumerable<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats;

Класс List<T> реализует интерфейс IEnumerable<T>, поэтому List<Cat> реализует IEnumerable<Cat>. А ковариантный параметр типа делает всё остальное.

Котравариантность позволяет вам использовать более общий (базовый) тип, чем изначально обозначенный. Вы можете присвоить экземпляр делегата Action<Animal> переменной типа Action<Cat>.
Контравариантность выглядит контринтуитивной. В следующем примере создаётся делегат типа Action<Animal>, а затем он присваивается переменной типа Action<Cat>.
Action<Animal> actAnimal = (target)=>{Console.WriteLine(target.GetType().Name);};
Action<Cat> actCat = actAnimal;
actCat(new Cat()); // выводит “Cat”

Лямбда-выражение создаёт метод-делегат, который принимает один параметр типа Animal, и у которого нет возвращаемого значения. Этот делегат может быть присвоен переменной типа Action<Cat>, поскольку параметр T делегата Action<T> контравариантен. Когда делегат типа Action<Animal> вызывается так, как если бы он был типа Action<Cat>, его аргумент должен быть типа Cat.

В общем случае ковариантный параметр типа может быть использован в качестве типа возвращаемого значения делегата, а контравариантный – как тип параметра. В случае интерфейсов ковариантные параметры типа могут быть использованы как типы возвращаемых значений методов интерфейса, а контравариантные – как типы параметров методов интерфейса.

Продолжение следует…

Источник: https://docs.microsoft.com/ru-ru/dotnet/standard/generics/covariance-and-contravariance
  • 👍 1
More from @netdeveloperdiary
  1. Oct 1, 2026Post #3357
  2. Sep 30, 2026Post #3356
  3. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
  4. Sep 29, 2026День 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная ко…
  5. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
  6. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →