如何转发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,因为GlobalOnBoardingStepOneHandlerinheritance自BaseStepHandler ,而不是BaseStepHandler 。 这可能是.NETgenerics中最常见的错误。 generics对于类型参数不是协变的。

看到:

C#:强制转换为基类型的通用接口

http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-two.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx

等等…

问题是你假设因为GlobalOnBoardingStepOneDataModelinheritance自BaseStepDataModel ,所以GlobalOnBoardingStepOneHandlerinheritance自BaseStepHandler 。 事实并非如此,所以你不能从一个投射到另一个。

例如,请考虑以下事项:

 var myListOfStrings = new List(); // By your logic, this should compile (it doesn't): var myListOfObjects = ((List)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? 

现在,这对于恢复Java程序员来说非常困惑,因为这在Java中是可行的 。 在Java中,您有类型擦除,因此在运行时List实际上只是一个List ,因此您可以将它转换为您喜欢的任何内容,并将您想要的任何内容放入其中。 因为CLR使用reifiedgenerics而不是类型擦除,所以List实际上是与ListList分离且不同的类型

这里的问题是你期望具体类型通用参数的逆变 协方差

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

你可以设计一个这样的标记界面:

 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` too! 

要了解有关协方差的更多信息,请访问以下链接: http : //msdn.microsoft.com/en-us/library/ee207183.aspx