如何上传泛型类型参数 [英] How to upcast generic type parameters
问题描述
BaseStepHandler< BaseStepDataModel>在这种情况下,当我使用反射时,创建的类型可以是许多泛型类型。 activator =(BaseStepHandler< BaseStepDataModel>)Activator.CreateInstance(....);
创建的实例可以是BaseStepDataModel的所有子元素。
BaseStepHandler< OneDataModel>
或
BaseStepHandler< TwoDataModel>
OneDataModel和TwoDataModel扩展了BaseStepDataModel。
这是我得到的异常:
无法投射类型为'.... GlobalOnBoardingStepOneHandler '输入'.... BaseStepHandler`1 [.... BaseStepDataModel]'。
这是声明if GlobalOnBoardingStepOneHandler。
public class GlobalOnBoardingStepOneHandler:BaseStepHandler< GlobalOnBoardingStepOneDataModel> {}
BaseStepHandler< GlobalOnBoardingStepOneDataModel> $ class =h2_lin>解决方案
,而不是 BaseStepHandler< BaseStepDataModel>
。这可能是.NET泛型最常见的错误。泛型对于类型参数不是协变的。
请参阅:
http:// blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
等...
问题在于你假设因为 GlobalOnBoardingStepOneDataModel
继承于 BaseStepDataModel
, GlobalOnBoardingStepOneHandler
继承自 BaseStepHandler< BaseStepDataModel>
的。那根本不是这种情况,所以你不能从一个转到另一个。
作为一个例子,请考虑以下几点:
var myListOfStrings = new List< String>();
//根据你的逻辑,这应该编译(它不会):
var myListOfObjects =((List< Object>)myListOfStrings);
//但是如果是这样的话,这将是可能的:
myListOfObjects.Add(1); //圣牛,我刚刚添加了一个整数到字符串列表!世界到底是什么?
现在,这对于恢复Java程序员来说非常混乱,因为 STRONG>。在Java中,你有类型擦除,所以在运行时,一个 List< String>
实际上只是一个 List< Object>
,所以你可以将它投射到任何你喜欢的东西上,然后把你想要的任何东西放进去。因为CLR使用了泛化泛型,而不是类型擦除,所以 List< String>
实际上是一个与 List< Object> code>或
列表<整数>
When I use reflection in this case, the created type can be many generic types.
BaseStepHandler<BaseStepDataModel> activator = (BaseStepHandler<BaseStepDataModel>)Activator.CreateInstance(....);
The created instance can be all childs of BaseStepDataModel.
BaseStepHandler<OneDataModel>
OR
BaseStepHandler<TwoDataModel>
OneDataModel and TwoDataModel are extending BaseStepDataModel.
this is the exception that I get:
Unable to cast object of type '....GlobalOnBoardingStepOneHandler' to type '....BaseStepHandler`1[....BaseStepDataModel]'.
this is the declaration if GlobalOnBoardingStepOneHandler.
public class GlobalOnBoardingStepOneHandler : BaseStepHandler<GlobalOnBoardingStepOneDataModel>{}
You are getting the exception because GlobalOnBoardingStepOneHandler
inherits from BaseStepHandler<GlobalOnBoardingStepOneDataModel>
, not BaseStepHandler<BaseStepDataModel>
. This is probably the most common mistake with .NET generics. Generics are not covariant for type parameters.
See:
C#: cast to generic interface with base type
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
etc...
The issue is that you assume that because GlobalOnBoardingStepOneDataModel
inherits from BaseStepDataModel
, that GlobalOnBoardingStepOneHandler
inherits from BaseStepHandler<BaseStepDataModel>
. That simply isn't the case, and so you can't cast from one to the other.
As an example, consider the following:
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?
Now, this is very confusing for recovering Java programmers because this is possible in Java. In Java, you have type erasure, so that at runtime a List<String>
is actually just a List<Object>
, and so you can cast it to anything you like, and put anything you want into it. Because the CLR uses reified generics, not type erasure, a List<String>
is actually a separate and distinct type from a List<Object>
or a List<Integer>
这篇关于如何上传泛型类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!