在C#中,协变(covariance)和逆变(contravariance)是两种类型参数变化的形式,它们主要用于泛型接口和委托中,以支持更加灵活的类型转换。
协变允许将派生类的实例赋值给基类的 引用,这在泛型接口和委托的返回类型中特别有用。通过使用out
关键字来标记泛型接口或委托中的泛型参数,可以实现协变。
例如,假设有一个表示泛型集合的接口IEnumerable<out T>
,其中T
是一个泛型参数。由于这个接口使用了out
关键字,T
被认为是协变的。这意味着,如果有一个IEnumerable<Derived>
的实例,您可以将其隐式转换为IEnumerable<Base>
,其中Derived
是Base
的派生类。
IEnumerable<Derived> derivedList = new List<Derived>();
IEnumerable<Base> baseList = derivedList; // 协变,因为IEnumerable<T>中的T是out参数
逆变则允许您将基类的实例赋值给派生类的引用,这在泛型接口和委托的参数类型中特别有用。通过使用in
关键字来标记泛型接口或委托中的泛型参数,您可以实现逆变。
例如,假设有一个泛型接口IComparer<in T>
,用于比较两个T
类型的对象。由于这个接口使用了in
关键字,T
被认为是逆变的。这意味着,如果有一个IComparer<Base>
的实例,可以将其隐式转换为IComparer<Derived>
,其中Derived
是Base
的派生类。
IComparer<Base> baseComparer = new BaseComparer();
IComparer<Derived> derivedComparer = baseComparer; // 逆变,因为IComparer<T>中的T是in参数
两者实质上都遵循里氏替换原则