C#——协变和逆变

阳光穿透心脏的1/2处 2023-01-02 13:29 293阅读 0赞

C#——协变和逆变

在 C# 中,协变和逆变能够实现数组类型、委托类型和泛型类型参数的隐式引用转换。 协变保留分配兼容性,逆变则与之相反。

以下代码演示分配兼容性、协变和逆变之间的差异。

  1. // Assignment compatibility.
  2. string str = "test";
  3. // An object of a more derived type is assigned to an object of a less derived type.
  4. object obj = str;
  5. // Covariance.
  6. IEnumerable<string> strings = new List<string>();
  7. // An object that is instantiated with a more derived type argument
  8. // is assigned to an object instantiated with a less derived type argument.
  9. // Assignment compatibility is preserved.
  10. IEnumerable<object> objects = strings;
  11. // Contravariance.
  12. // Assume that the following method is in the class:
  13. // static void SetObject(object o) { }
  14. Action<object> actObject = SetObject;
  15. // An object that is instantiated with a less derived type argument
  16. // is assigned to an object instantiated with a more derived type argument.
  17. // Assignment compatibility is reversed.
  18. Action<string> actString = actObject;

数组的协变使派生程度更大的类型的数组能够隐式转换为派生程度更小的类型的数组。 但是此操作不是类型安全的操作,如以下代码示例所示。

  1. object[] array = new String[10];
  2. // The following statement produces a run-time exception.
  3. // array[0] = 10;

对方法组的协变和逆变支持允许将方法签名与委托类型相匹配。 这样,不仅可以将具有匹配签名的方法分配给委托,还可以分配与委托类型指定的派生类型相比,返回派生程度更大的类型的方法(协变)或接受具有派生程度更小的类型的参数的方法(逆变)。

以下代码示例演示对方法组的协变和逆变支持。

  1. static object GetObject() {
  2. return null; }
  3. static void SetObject(object obj) {
  4. }
  5. static string GetString() {
  6. return ""; }
  7. static void SetString(string str) {
  8. }
  9. static void Test()
  10. {
  11. // Covariance. A delegate specifies a return type as object,
  12. // but you can assign a method that returns a string.
  13. Func<object> del = GetString;
  14. // Contravariance. A delegate specifies a parameter type as string,
  15. // but you can assign a method that takes an object.
  16. Action<string> del2 = SetObject;
  17. }

在 .NET Framework 4 或更高版本中,C# 支持在泛型接口和委托中使用协变和逆变,并允许隐式转换泛型类型参数。

  1. IEnumerable<String> strings = new List<String>();
  2. IEnumerable<Object> objects = strings;

如果泛型接口或委托的泛型参数被声明为协变或逆变,该泛型接口或委托则被称为“变体”。 凭借 C#,能够创建自己的变体接口和委托。

发表评论

表情:
评论列表 (有 0 条评论,293人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JAVA中的

    协变逆变的概念 可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用。如果不能将一个类型替换成为另一个类型,那么这个类型就称之为:不变量。 协变:如果某个返回的

    相关 Typescript中的

    最近用TS时碰到协变和逆变的一些概念,发现有篇外国人写的文章比较容易理解的,这里记录下。 1. 协变和逆变简单理解 先简单说下协变和逆变的理解。 首先,无论协变还是逆

    相关 之疑问

    前言 关于协变和逆变已经有很多园友谈论过了,学习时也参考过园友们的文章,非常之到位!这个问题可能对您而言很简单,若有解释,请告知,在此感谢。高手绕道! 既然是标题是协变

    相关 深入理解 C#

    msdn 解释如下:  “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。  “逆变”则是指能够使用派生程度更小的类型。  解释的很正确,大致就是这样,不

    相关 详解

    逆变(`contravariant`)与协变(`covariant`)是`C4`新增的概念,许多书籍和博客都有讲解,我觉得都没有把它们讲清楚,搞明白了它们,可以更准确地去定义泛