在这种情况下,当我使用反射时,创建的类型可以是许多泛型类型。
BaseStepHandler<BaseStepDataModel> activator = (BaseStepHandler<BaseStepDataModel>)Activator.CreateInstance(....);
创建的实例可以是BaseStepDataModel的所有子项。
BaseStepHandler<OneDataModel>
OR
BaseStepHandler<TwoDataModel>
OneDataModel和TwoDataModel正在扩展BaseStepDataModel。
这是我得到的例外:
无法将类型为'.... GlobalOnBoardingStepOneHandler'的对象转换为'.... BaseStepHandler`1 [.... BaseStepDataModel]'。
这是GlobalOnBoardingStepOneHandler的声明。
public class GlobalOnBoardingStepOneHandler : BaseStepHandler<GlobalOnBoardingStepOneDataModel>{}
答案 0 :(得分:4)
您收到例外是因为GlobalOnBoardingStepOneHandler
继承自BaseStepHandler<GlobalOnBoardingStepOneDataModel>
,而不是BaseStepHandler<BaseStepDataModel>
。这可能是.NET泛型中最常见的错误。泛型对于类型参数不是协变的。
请参阅:
C#: cast to generic interface with base type
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>();
// 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?
现在,这对于恢复Java程序员来说非常困惑,因为这在Java中是可行的。在Java中,您有类型擦除,因此在运行时List<String>
实际上只是List<Object>
,因此您可以将其转换为您喜欢的任何内容,并将您想要的任何内容放入其中。由于CLR使用的是定义的泛型,而不是类型擦除,List<String>
实际上是与List<Object>
或List<Integer>
答案 1 :(得分:3)
这里的问题是你期望具体类型通用参数的 contravariance covariance 。
基本上,你永远不会使用具体类型实现目标,但有一个解决方法。
您可以设计这样的标记界面:
public interface IBaseStepHandler<out T> // "out" marks T as covariant
where T : BaseDataModel // Do you have a model base type? ;)
{
// Declare members here
}
我说“在这里声明成员”,只需声明这些成员,这些成员是你的具体基类(我说的是“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!
要了解有关协方差的更多信息,请点击以下链接:http://msdn.microsoft.com/en-us/library/ee207183.aspx