如何将类型转换为通用基类型

时间:2015-12-23 20:54:37

标签: c# generics

我有代码结构:

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。这是否有可能实现?

3 个答案:

答案 0 :(得分:3)

问题是类型安全。我们假设我们有 Fruit 类和其他2个来自 Apple Cocunut 的类。以下示例来自 C#5.0 Unleashed book。

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();

如示例所示,当让类型参数用于输入时,类型安全性被破坏。由于椰子是水果,我们能够将它输入Apple阵列,因为我们将Apple阵列转换为Fruit阵列。当使用Fruit数组引用时,我们能够在Apple中插入Coconut。当我们在椰子上调用Peel方法时,我们得到一个错误,因为椰子没有Peel方法。这打破了类型安全。为避免这种情况,请键入参数&#39;必须通过在T 中指出 out T 来表示使用输入或输出。如果您定义为 out T ,则可以仅将T用作方法的返回值。如果您在T 中定义为,则只能在输入位置使用T.这样就建立了类型安全性。如果您需要使用T作为输入和输出,那么您无法进行所需的演员表,因为它会打破类型安全。

答案 1 :(得分:3)

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界面上的某些操作,例如void Add(T t)中不允许使用IBase等方法。

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

答案 2 :(得分:0)

是的但您必须遍历类型的层次结构堆栈以确定或构建执行转换检查以确定您所追求的内容的代码。