如何将类型转换为它';的泛型基类型

本文关键字:泛型 基类 类型 类型转换 | 更新日期: 2023-09-27 18:27:57

我有代码结构:

SpecificType.cs

public class SpecificType : TypeBase<SpecificT, SpecificV>
    where T : ITBase
    where V : IVBase
{ ... }

SpecificT.cs

public class SpecificT : ITBase { ... }

SpecificV.cs

public class SpecificV : IVBase { ... }

TypeBase.cs

public class TypeBase<T, V> : IBase<T, V>
    where T : ITBase
    where V : IVBase
{ ... }

IBase.cs

public interface IBase<T, V>
    where T : ITBase
    where V : IVBase
{ ... }

我只想把我的SpecificType转换成它最抽象的类型——IBase<T,V>:

SpecificType specTypeObject = new SpecificType();
IBase<ITBase, IVBase> typeObject = (IBase<ITBase, IVBase>)specTypeObject;

我收到的只是InvalidCastException。这是我想要实现的吗?

如何将类型转换为它';的泛型基类型

问题是类型安全。假设我们有Fruit类和其他两个派生自AppleCocunste的类。以下示例来自C#5.0 Unleashed一书。

Apple[] apples = new Apple[] { apple1, apple2, apple3 };
// Because of array type covariance we can write the following.
Fruit[] fruits = apples;
// We're putting a Coconut, which is a Fruit, in a Fruit array. This is   fine.
fruits[2] = new Coconut();
// An element of an Apple[] should be an Apple, right?
apples[2].Peel();

如示例所示,当允许类型参数用于输入时,类型安全性被破坏。由于椰子是一种水果,我们能够将其输入到苹果数组中,因为我们将苹果数组下放到了水果数组中。当使用Fruit数组引用时,我们能够在苹果中插入椰子。当我们在椰子上调用Peel方法时,我们会得到一个错误,因为椰子没有Peel方法。这破坏了类型安全性。为了避免这种情况,类型参数的使用必须通过在T中说来表示为输入或输出。如果定义为out T,则只能使用T作为方法的返回值。如果在T中定义为,则只能在输入位置使用T。通过这种方式建立了类型安全。如果您需要对输入和输出都使用T,那么您就无法执行所需的强制转换,因为它破坏了类型安全性。

SpecificType specTypeObject = new SpecificType();
IBase<ITBase, IVBase> typeObject = (IBase<ITBase, IVBase>)specTypeObject;

无法执行此强制转换,因为SpecificType的类型不是IBase<ITBase, IVBase>SpecificType实际上有一个IBase<SpecificT, SpecificV的基本类型,因此以下工作:

SpecificType specTypeObject = new SpecificType();       
IBase<SpecificT, SpecificV> typeObject = (IBase<SpecificT, SpecificV>)specTypeObject;

您可以添加协方差说明符使其发挥作用:

public interface IBase<out T, out V>
    where T : ITBase
    where V : IVBase
    {}
var specTypeObject = new SpecificType();
var typeObject = (IBase<ITBase, IVBase>)specTypeObject;

现在这就行了。不过,这可能会阻止在IBase接口上执行某些操作,例如IBase中不允许使用类似void Add(T t)的方法。

此外,为了完整起见,请注意,不能将协方差或逆变换应用于泛型类,只能应用于接口和委托。因此以下内容不起作用:public class TypeBase<out T, out V> : IBase<T, V>

是的,但您必须遍历类型的层次结构堆栈来确定或构建执行强制转换检查的代码,以确定您想要什么。