泛型的协变(Covariance)和逆变(Contravariance)

一、什么是协变和逆变

如果存在一个泛型接口Interface<T>

它的泛型参数的子类型IInterface<Dog>可以安全的转换成泛型父类型的IInterface<Animal>

这个过程就称为协变

如果存在一个泛型接口IInterface<T>

它的泛型参数的父类型IInterface<Animal>可以安全的转换成泛型子类型的IInterface<Dog>

这个过程就成为逆变

我们先明确两个术语:

协变(Covariance):保持类型顺序。如果 DogAnimal 的子类,那么 IEnumerable<Dog> 可以被视为 IEnumerable<Animal>

逆变(Contravariance):反转类型顺序。如果 DogAnimal 的子类,那么 Action<Animal> 可以被视为 Action<Dog>

协变与逆变解决的问题

假设你有如下类层次:

csharp 复制代码
class Animal { }
class Dog : Animal { }

❌ 没有协变/逆变时的问题

在没有协变的情况下,以下代码会编译失败:

csharp 复制代码
List<Dog> dogs = new List<Dog>();

// 编译错误!List<Dog> 不能赋值给 List<Animal>
List<Animal> animals = dogs;

因为泛型默认是 不变(Invariant) 的,即 List<Dog>List<Animal> 没有继承关系。

但直觉上,狗的列表"应该是"动物列表的一种。协变就是为了解决这种合理的类型转换需求,同时保证类型安全。

实际应用场景

协变: 你有一个 IReadOnlyList<IDocument>,但实际传入的是 IReadOnlyList<PdfDocument>,协变让它可以接受。
逆变: 你有一个排序器IComparer<object>,它可以用于比较任何对象,包括 stringPerson,所以可以赋值给 IComparer<string>

C# 使用 out 和 in 关键字来声明协变和逆变:

out T:表示 协变(Covariance),T 只能作为方法的返回值(输出)。
in T :表示 逆变(Contravariance),T 只能作为方法的参数(输入)。

相关推荐
JustCheng10 小时前
Dispacher(1/2)深入解析-详细使用
c#
CoderIsArt1 天前
C#中UI 线程与 Dispatcher
开发语言·ui·c#
呆呆敲代码的小Y2 天前
【游戏开发】Lua 与 C# 交互原理解析
c#·lua·交互·热更新·lua与c#交互·游戏热更新
用户298698530142 天前
PDF 转纯文本(TXT)免费攻略:轻松提取文字内容
人工智能·后端·c#
呆呆敲代码的小Y2 天前
【游戏开发】C# 中的迭代器
java·开发语言·c#·迭代器
格林威2 天前
C# 相机Burst模式图像采集:使用相机内存配合OpenCvSharp和Halcon实现短时间的高速采集的方法
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机
J总裁的小芒果2 天前
参数过多-分批传参
c#
典典分享指南2 天前
短视频分镜提示词:让 AI 出片的产品口播
java·c#·bash·composer·symfony
Z5998178412 天前
c#软件开发学习笔记--WPF(Canvas、数据绑定、MVVM模式、值转换器)
笔记·学习·c#