­

C#2.0新增功能06 协变和逆变

  • 2019 年 10 月 4 日
  • 筆記

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

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

// 分配兼容性.  string str = "test";  // 将派生类型更高的对象分配给派生类型更低的对象  object obj = str;    IEnumerable<string> strings = new List<string>();  // 用派生类型参数实例化的对象被分配给用派生类型参数实例化的对象。// 分配兼容性保持不变。  IEnumerable<object> objects = strings;    // 逆变.  // 假设以下方法在类中:static void SetObject(object o) { }  Action<object> actObject = SetObject;  // 使用派生程度较低的类型参数实例化的对象被分配给使用派生程度较高的类型参数实例化的对象。// 分配兼容性被反转.  Action<string> actString = actObject;

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

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

static object GetObject() { return null; }  static void SetObject(object obj) { }    static string GetString() { return ""; }  static void SetString(string str) { }    static void Test()  {      // 协变. 委托将返回类型指定为对象,但可以指定返回字符串的方法。      Func<object> del = GetString;        // 逆变. 委托将参数类型指定为字符串,但可以指定接受对象的方法。      Action<string> del2 = SetObject;  }

在 .NET Framework 4 或较新的 C# 中,支持在泛型接口和委托中使用协变和逆变,并允许隐式转换泛型类型参数。 有关详细信息,请参阅泛型接口中的变体 (C#)委托中的变体 (C#)《C#4.0新增功能03 泛型中的协变和逆变》

以下代码示例演示泛型接口的隐式引用转换。

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

如果泛型接口或委托的泛型参数被声明为协变或逆变,该泛型接口或委托则被称为“变体”。 凭借 C#,能够创建自己的变体接口和委托。 有关详细信息,请参阅创建变体泛型接口 (C#)委托中的变体 (C#)

相关主题

Title

说明

泛型接口中的变体 (C#)

讨论泛型接口中的协变和逆变,提供 .NET Framework 中的变体泛型接口列表。

创建变体泛型接口 (C#)

演示如何创建自定义变体接口。

在泛型集合的接口中使用变体 (C#)

演示 IEnumerable<T> 接口和 IComparable<T> 接口中对协变和逆变的支持如何帮助重复使用代码。

委托中的变体 (C#)

讨论泛型委托和非泛型委托中的协变和逆变,并提供 .NET Framework 中的变体泛型委托列表。

使用委托中的变体 (C#)

演示如何使用非泛型委托中的协变和逆变支持以将方法签名与委托类型相匹配。

对 Func 和 Action 泛型委托使用变体 (C#)

演示 Func 委托和 Action 委托中对协变和逆变的支持如何帮助重复使用代码。