C#面试题更新 2026-08-05

在 C# 中,泛型集合的协变与逆变各自代表什么含义?它们之间又有哪些不同之处?

技术原理C#

考察说明

考察对 C# 泛型类型参数变体性的理解程度以及区分协变与逆变的能力。

回答思路

  1. 【回答框架 1】协变是指在泛型类型中,类型参数允许使用其派生类型替换基类型,仅适用于返回类型位置,使用 out 关键字标记。逆变则相反,允许使用基类型替换派生类型,仅适用于输入位置,使用 in 关键字标记。
  2. 【回答框架 2】在 .NET 中,IEnumerable<out T> 和 IReadOnlyList<out T> 是协变示例,而 IComparer<in T> 和 IEqualityComparer<in T> 是逆变示例。协变使得 IEnumerable<string> 可以隐式转换为 IEnumerable<object>,逆变则使 IComparer<object> 可以用于 IComparer<string> 的场景。
  3. 【回答框架 3】泛型委托也支持变体,例如 Func<out TResult> 是协变的,Action<in T> 是逆变的。其核心区别在于协变适合“生产者”场景,逆变适合“消费者”场景,这与 Liskov 替换原则相关,但需要注意引用类型才支持变体,值类型不参与。
  4. 【回答框架 4】在自定义接口或委托中,需要显式使用 out 或 in 关键字,编译器会检查类型参数的使用位置,确保 out 参数仅出现在返回位置,in 参数仅出现在输入位置,违反规则会导致编译错误。
  5. 【关键点 1】协变用 out,逆变用 in,分别对应返回和输入位置。
  6. 【关键点 2】IEnumerable<T> 协变,IComparer<T> 逆变。
  7. 【关键点 3】变体仅适用于引用类型,值类型不具备协变逆变。
  8. 【关键点 4】自定义变体需满足类型参数使用位置的约束。
  9. 【易错点 1】易将数组协变与泛型协变混淆,数组协变存在类型安全问题。
  10. 【易错点 2】忽略值类型不支持变体的事实,导致误用。
  11. 【易错点 3】误以为协变逆变可以双向使用,实际上只能单向。