.NET 4.0 C# 泛型协变与反变详解

一颗松果
一颗松果
发布时间:2026-10-13 | 5人浏览过
原创

本文详细介绍 .NET 4.0 中 C# 泛型类型的协变(covariant)和反变(contravariant)特性。重点讲解 `in` 和 `out` 关键字在泛型接口中的应用规则、方法参数与返回值的相互影响机制,以及值类型的限制条件。

背景:理解协变与反变的本质

可变性(Variance)源于类型间的绑定关系。以数组为例,若类型 T 继承自类型 U,则数组 T[] 也可以隐式转换为 U[],这种同向转换称为协变(Covariant)。

在泛型中,由于泛型类/结构体不支持协变,我们通过泛型接口来实现:

  • 协变(Covariant):子类引用转换为父类引用(如 IChild 转为 IParent),方向相同。
  • 反变(Contravariant):父类引用转换为子类引用(如 IParent 转为 IChild),方向相反。

.NET 4.0 泛型协变与反变实战

为了解决泛型接口直接使用导致的类型不安全(例如将父类传给仅接收子类的参数),.NET 4.0 引入了 in 和 out 修饰符来明确限定类型参数的作用域。

第1步:声明协变接口(用于返回值)

当类型参数仅作为方法的返回值出现时,该参数支持协变。使用 out 关键字标记:


interface ICo<out T>
{
    // T 只能出现在返回值位置
    T Method();
}

此时,ICo<string> 可安全地视为 ICo<object>。

第2步:声明反变接口(用于方法参数)

当类型参数仅作为方法的输入参数出现时,该参数支持反变。使用 in 关键字标记:


interface IContra<in T>
{
    // T 只能出现在参数位置
    void Method(T param);
}

此时,IContra<object> 可安全地视为 IContra<string>。

第3步:混合使用 In/Out 并调用

一个接口可以同时包含 in 和 out 参数。例如:IBar<in T1, out T2> 对 T1 反变,对 T2 协变。调用时需同时考虑两者的转换:


// IBar<string, object> 可以转为 IBar<object, string>
// 因为 string -> object (协变), object -> string (反变)

核心难点:互换原则与一致原则

这是开发者最容易感到困惑的地方。尽管使用了 in 和 out,但它们在方法签名内部并非孤立存在。

第4步:遵循“协变-反变互换原则”处理参数

结论:如果一个接口 T 是协变的(out),那么它所包含的所有方法的参数类型必须是对 T 具有反变能力的类型。反之亦然。

示例说明:


interface IFoo<in T> { }

// 错误示例:IBar 声明为 in T,其内部方法 Test(IFoo<T> foo) 无法编译
// 因为 T 要传递给 IFoo<T>,而 IFoo 是反变的,这会导致逻辑冲突

// 正确示例:IBar 声明为 out T
interface IBar<out T>
{
    void Test(IFoo<T> foo); // 合法!IFoo 的反变性补偿了 IBar 的协变性
}

第5步:遵循“协变-反变一致原则”处理返回值

结论:如果一个接口需要对类型 T 进行协变或反变,那么所有方法的返回值类型也必须支持与 T 相同方向的可变性。


interface IFooCo<out T> { }
interface IFooContra<in T> { }

// 错误示例:如果 Test1() 返回的是 IFooContra<T>,编译器会报错
// 因为 IBar 要求 T 协变,但其返回值 IFooContra 是反变的,两者不一致
interface IBar<out T>
{
    IFooCo<T> Test1(); // 返回类型也必须是协变的
}

关键注意事项与限制

在实际开发中使用泛型协变与反变时,请务必注意以下边界情况:

第6步:规避常见陷阱

  1. 仅泛型接口/委托有效:泛型类(Class)或泛型方法不支持此功能。
  2. 值类型不参与:由于装箱/拆箱机制的影响,值类型永远不参与协变或反变。List<int> 不能转为 List<object>。
  3. 属性读写限制:如果属性有 `get` 和 `set`,它同时包含了参数和返回值,因此不能使用单纯的 `in` 或 `out`,必须显式区分只读(getter only)与只写(setter only)以实现对应的约束。

以上就是 .NET 4.0 中 C# 泛型协变与反变的详细内容,更多关于 C# 高级特性优化程序设计的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表