通用类的协方差

本文关键字:方差 | 更新日期: 2023-09-27 18:06:06

在c#中有没有办法实现以下目标:

class MyClass<T>  where T : BaseTypeInner {}
class BaseTypeInner {}
class A : BaseTypeInner {}
class B : BaseTypeInner {}
void Main()
{
    MyClass<BaseTypeInner> variant;
    variant = new MyClass<A> (); // ERROR: Cannot implicitly convert type 'UserQuery.MyClass<UserQuery.A>' to 'UserQuery.MyClass<UserQuery.BaseTypeInner>'
    variant = new MyClass<B> ();
}

通用类的协方差

在c#中只有接口可以被修改。引用c#规范:

变量类型参数列表只能出现在接口和委托类型上。

所以你可以声明一个通用的协变接口IBaseClass<out T>,让BaseClass<T>实现它,然后强制转换到IBaseClass<BaseTypeInner>,而不是强制转换到类。

interface IMyClass<out T> where T : BaseTypeInner { }
class MyClass<T> : IMyClass<T> where T : BaseTypeInner { }
IMyClass<BaseTypeInner> variant;
variant = new MyClass<A>(); // works just fine
variant = new MyClass<B>();

一个可能的解决方案是为基泛型类型设置一个基类型:

class BaseType {}
class MyClass<T> : BaseType where T : BaseTypeInner {}
class BaseTypeInner {}
class A : BaseTypeInner {}
class B : BaseTypeInner {}
void Main()
{
    BaseType variant;
    variant = new MyClass<A> ();
    variant = new MyClass<B> ();
}

但是,这不是一个好主意,因为我使用的是一个较低的类,它不是泛型的,所以我失去了使用类型参数所获得的所有细节和限制。

不可以,但是可以提供自定义CastUp/CastDown方法来实现这一点。ImmutableArray<T>是。net BCL的一部分。