Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.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# 如何向上转换泛型类型参数_C#_Generics - Fatal编程技术网

C# 如何向上转换泛型类型参数

C# 如何向上转换泛型类型参数,c#,generics,C#,Generics,在本例中使用反射时,创建的类型可以是许多泛型类型 BaseStepHandler<BaseStepDataModel> activator = (BaseStepHandler<BaseStepDataModel>)Activator.CreateInstance(....); BaseStepHandler激活器=(BaseStepHandler)activator.CreateInstance(…); 创建的实例可以是BaseStepDataModel的所有子对象

在本例中使用反射时,创建的类型可以是许多泛型类型

BaseStepHandler<BaseStepDataModel> activator = (BaseStepHandler<BaseStepDataModel>)Activator.CreateInstance(....);
BaseStepHandler激活器=(BaseStepHandler)activator.CreateInstance(…);
创建的实例可以是BaseStepDataModel的所有子对象

BaseStepHandler

BaseStepHandler

OneDataModel和TwoDataModel是BaseStepDataModel的扩展

这是我得到的一个例外:

无法将类型为“..GlobalOnBoardingStepOneHandler”的对象强制转换为类型为“..BaseStepHandler`1[..BaseStepDataModel]”

这是GlobalOnBoardingStepOneHandler的声明

public class GlobalOnBoardingStepOneHandler : BaseStepHandler<GlobalOnBoardingStepOneDataModel>{}
公共类GlobalOnBoardingStepOneHandler:BaseStepHandler{}

您获得异常是因为
GlobalOnBoardingStepOneHandler
继承自
BaseStepHandler
,而不是
BaseStepHandler
。这可能是.NET泛型最常见的错误。泛型对于类型参数不是协变的

见:

等等

问题在于,您假设由于
GlobalOnBoardingStepOneDataModel
继承自
BaseStepDataModel
,因此
GlobalOnBoardingStepOneHandler
继承自
BaseStepHandler
。事实并非如此,因此你不能从一个角色转换到另一个角色

作为一个例子,考虑如下:

var myListOfStrings = new List<String>();

// By your logic, this should compile (it doesn't):
var myListOfObjects = ((List<Object>)myListOfStrings);

// But if it did, this would be possible:
myListOfObjects.Add(1); // Holy cow, I just added an integer to a list of strings!  What is the world coming to?
var myListOfStrings=new List();
//按照您的逻辑,应该编译(它不会):
var myListOfObjects=((列表)myListOfStrings);
//但如果真的这样做了,这将是可能的:
myListOfObjects.Add(1);//天哪,我刚刚在字符串列表中添加了一个整数!世界将走向何方?

现在,这对于恢复Java程序员来说非常混乱,因为这在Java中是可能的。在Java中,您可以使用类型擦除,因此在运行时,
列表实际上只是一个
列表
,因此您可以将其强制转换为任何您喜欢的内容,并将任何您想要的内容放入其中。因为CLR使用具体化的泛型,而不是类型擦除,
列表
实际上是与
列表
列表
不同的独立类型。这里的问题是,您期望具体类型泛型参数具有反方差协方差

基本上,使用具体类型永远无法实现目标,但有一个解决方法

您可以这样设计标记器界面:

public interface IBaseStepHandler<out T> // "out" marks T as covariant
   where T : BaseDataModel // Do you have a model base type? ;)
{
     // Declare members here
}
公共接口IBaseStepHandler//“out”将T标记为协变
其中T:BaseDataModel//您有模型基类型吗?;)
{
//在此宣布成员
}
如果我说“在这里声明成员”,只需声明这些成员,它们是您的具体基类的一部分(我说的是“BaseStepHandler”)

之后,在基类BaseStepHandler中实现该接口

现在,您可以做您想做的事情:

IBaseStepHandler<BaseDataModel> some = new WhateverBaseStepHandlerClass(); 

// This is possible because T generic parameter is covariant and it can be casted to `BaseDataModel`, or if you don't provide a `T` generic parameter constraint, you could cast it to `IBaseStepHandler<object>` too!
IBaseStepHandler some=newwhateverbasestephandlerclass();
//这是可能的,因为T泛型参数是协变的,可以将其强制转换为“BaseDataModel”,或者如果不提供“T”泛型参数约束,也可以将其强制转换为“IBaseStepHandler”!

为了了解更多关于协方差的信息,请点击以下链接:

@JoachimIsaksson-查看主题(我还添加了例外)@JoachimIsaksson我相信任何人都应该理解OP的要求。@MatíasFidemraizer现在,是的,没有例外和类型的定义,不。不过现在一切都好了:)我不明白,请解释一下。对于具体类的泛型参数,没有逆变换/协变支持。也许这是一个错误,但我发现它更多的是一个缺失的功能,或者是一个不可能实现的功能。你认为替代解决方案是什么?没有“快速修复”替代解决方案。你需要重新审视你的设计。@MatíasFidemraizer这是一个不切实际的特性;泛型类/结构几乎完全不适合协变或逆变,尽管可以构造一些微不足道的反例。您可以很容易地使用接口来容纳反例,因此支持类和/或结构中的差异并没有多大好处。当然,这假设他只是以协变方式使用他的
BaseDataModel
。如果他不是,这甚至不会编译。@ChrisShain,但也许解决他的问题会迫使他重构代码,所以他避免了这个问题。。。这取决于他。。。我想向他展示一种实现目标的方法,很遗憾,没有人能想象他的范围和其他问题……我并不是说你错了——事实上,当我输入这个时,我正在投票给你。我只是指出这不是灵丹妙药。@ChrisShain完全同意,这不是灵丹妙药,这是饼干哈哈;)我理解您的意思,感谢您的投票。@MatíasFidemraizer
out
将类型参数声明为协变,而不是您在上一个代码示例的注释中所述的逆变。助记符:“co”->“o”->“out”;“反向“->”n“->”in”