Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将类型强制转换为它';s泛型基类型_C#_Generics - Fatal编程技术网

C# 如何将类型强制转换为它';s泛型基类型

C# 如何将类型强制转换为它';s泛型基类型,c#,generics,C#,Generics,我有代码结构: SpecificType.cs public class SpecificType : TypeBase<SpecificT, SpecificV> where T : ITBase where V : IVBase { ... } public class SpecificT : ITBase { ... } public class SpecificV : IVBase { ... } public class TypeBase<T,

我有代码结构:

SpecificType.cs

public class SpecificType : TypeBase<SpecificT, SpecificV>
    where T : ITBase
    where V : IVBase
{ ... }
public class SpecificT : ITBase { ... }
public class SpecificV : IVBase { ... }
public class TypeBase<T, V> : IBase<T, V>
    where T : ITBase
    where V : IVBase
{ ... }
public interface IBase<T, V>
    where T : ITBase
    where V : IVBase
{ ... }
specific v.cs

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

public class SpecificType : TypeBase<SpecificT, SpecificV>
    where T : ITBase
    where V : IVBase
{ ... }
public class SpecificT : ITBase { ... }
public class SpecificV : IVBase { ... }
public class TypeBase<T, V> : IBase<T, V>
    where T : ITBase
    where V : IVBase
{ ... }
public interface IBase<T, V>
    where T : ITBase
    where V : IVBase
{ ... }
我只想将我的
SpecificType
转换为它最抽象的类型-
IBase

SpecificType specTypeObject=new SpecificType();
IBase typeObject=(IBase)specTypeObject;

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

是的,但您必须向上遍历类型的层次结构堆栈,以确定或生成执行强制转换检查的代码,以确定您的目标。

是的,但您必须向上遍历类型的层次结构堆栈,以确定或生成执行强制转换检查的代码,以确定您的目标之后。

问题是类型安全。假设我们有水果类和从中衍生出的另外两个类苹果可可豆。下面的例子来自《C#5.0解放》一书

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

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

问题在于类型安全性。假设我们有水果类和从中衍生出的另外两个类苹果可可豆。下面的例子来自《C#5.0解放》一书

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();
SpecificType specTypeObject = new SpecificType();
IBase<ITBase, IVBase> typeObject = (IBase<ITBase, IVBase>)specTypeObject;
如示例所示,当让类型参数用于输入时,类型安全性被破坏。因为椰子是一种水果,所以我们能够将它输入到苹果数组中,因为我们将苹果数组下放到水果数组中。当使用水果数组引用时,我们能够在苹果中插入椰子。当我们在椰子上调用Peel方法时,我们得到一个错误,因为椰子没有Peel方法。这破坏了类型安全。为了避免这种情况,类型参数的使用必须通过在T
中说来表示为输入或输出。如果定义为out T,则只能将T用作方法的返回值。如果在T中定义为,则只能在输入位置使用T。这样就建立了类型安全性。如果需要对输入和输出都使用T,则无法执行所需的强制转换,因为它会破坏类型安全性

SpecificType specTypeObject = new SpecificType();
IBase<ITBase, IVBase> typeObject = (IBase<ITBase, IVBase>)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
where T:ITBase
其中V:IVBase
{}
var specTypeObject=新的SpecificType();
var typeObject=(IBase)specTypeObject;
现在这是可行的。这可能会阻止在
IBase
接口上执行某些操作,例如
IBase
中不允许使用类似
void Add(T)
的方法

另外,为了完整性起见,请注意,您不能将协方差或逆方差应用于泛型类,只能应用于接口和委托。因此以下操作不起作用:
公共类TypeBase:IBase


您可以添加协方差说明符以使其正常工作:

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

var specTypeObject = new SpecificType();
var typeObject = (IBase<ITBase, IVBase>)specTypeObject;
公共接口IBase
where T:ITBase
其中V:IVBase
{}
var specTypeObject=新的SpecificType();
var typeObject=(IBase)specTypeObject;
现在这是可行的。这可能会阻止在
IBase
接口上执行某些操作,例如
IBase
中不允许使用类似
void Add(T)
的方法


另外,为了完整性起见,请注意,您不能将协方差或逆方差应用于泛型类,只能应用于接口和委托。因此,以下操作不起作用:
公共类TypeBase:IBase

您能解释一下为什么我必须使用反射吗?我认为编译器很容易扩展继承层次结构。@Fk2阅读了C#中的协变和逆变。重要的是,
List
不是
List
的基本类型。如果您可以将
IBase
的类型参数声明为协变的,那么您可以做您想做的事情,但是如果在“输入”位置使用它们,您将无法将它们声明为协变的。我错调了,您必须使用
type
并向上移动它的声明堆栈,我的回答指出,您可以编写一些代码,对某些类型的实例进行测试,这些类型可以轻松确定基类。@phoog-您的回答让我理解了一个问题。@Fka我很高兴能够提供帮助。Eric Lippert的这一系列文章对我帮助很大:(他目前的博客位于)。你可能还想看看他在StackOverflow上的工作:你能解释一下为什么我必须使用反射吗?我认为编译器很容易扩展继承层次结构。@Fk2阅读了C#中的协变和逆变。重要的是,
List
不是
List
的基本类型。如果您可以将
IBase
的类型参数声明为协变的,那么您可以做您想做的事情,但是如果在“输入”位置使用它们,您将无法将它们声明为协变的。我错调了,您必须使用
type
并向上移动它的声明堆栈,我的回答指出,您可以编写一些代码,对某些类型的实例进行测试,这些类型可以轻松确定基类。@phoog-您的回答让我理解了一个问题。@Fka我很高兴