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íasFidemraizerout
将类型参数声明为协变,而不是您在上一个代码示例的注释中所述的逆变。助记符:“co”->“o”->“out”;“反向“->”n“->”in”