如何转发generics类型参数
当我在这种情况下使用reflection时,创建的类型可以是许多generics类型。
BaseStepHandler activator = (BaseStepHandler)Activator.CreateInstance(....);
创建的实例可以是BaseStepDataModel的所有子项。
BaseStepHandler
OR
BaseStepHandler
OneDataModel和TwoDataModel正在扩展BaseStepDataModel。
这是我得到的例外:
无法将’…. GlobalOnBoardingStepOneHandler’类型的对象转换为’…. BaseStepHandler`1 […. BaseStepDataModel]’。
这是GlobalOnBoardingStepOneHandler的声明。
public class GlobalOnBoardingStepOneHandler : BaseStepHandler{}
您将获得exception,因为GlobalOnBoardingStepOneHandler
inheritance自BaseStepHandler
,而不是BaseStepHandler
。 这可能是.NETgenerics中最常见的错误。 generics对于类型参数不是协变的。
看到:
C#:强制转换为基类型的通用接口
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
等等…
问题是你假设因为GlobalOnBoardingStepOneDataModel
inheritance自BaseStepDataModel
,所以GlobalOnBoardingStepOneHandler
inheritance自BaseStepHandler
。 事实并非如此,所以你不能从一个投射到另一个。
例如,请考虑以下事项:
var myListOfStrings = new List(); // By your logic, this should compile (it doesn't): var myListOfObjects = ((List
现在,这对于恢复Java程序员来说非常困惑,因为这在Java中是可行的 。 在Java中,您有类型擦除,因此在运行时List
实际上只是一个List
,因此您可以将它转换为您喜欢的任何内容,并将您想要的任何内容放入其中。 因为CLR使用reifiedgenerics而不是类型擦除,所以List
实际上是与List
或List
分离且不同的类型
这里的问题是你期望具体类型通用参数的逆变 协方差 。
基本上,你不会永远不会使用具体的类型实现你的目标,但有一个解决方法。
你可以设计一个这样的标记界面:
public interface IBaseStepHandler // "out" marks T as covariant where T : BaseDataModel // Do you have a model base type? ;) { // Declare members here }
我在这里说“在这里声明成员”,只是声明这些成员是你的具体基类的一部分(我说的是“BaseStepHandler”)。
之后,在基类BaseStepHandler中实现此接口。
现在,你可以做你想做的事:
IBaseStepHandler 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
要了解有关协方差的更多信息,请访问以下链接: http : //msdn.microsoft.com/en-us/library/ee207183.aspx