2012-01-24 45 views
0

当我在这种情况下使用反射时,创建的类型可以是许多通用类型。如何上传通用类型参数

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>{} 
+2

问题是什么? –

+0

@JoachimIsaksson - 查看主题(我也添加了例外) – SexyMF

+0

@JoachimIsaksson我相信任何人都应该明白OP的要求。 –

回答

4

你所得到的异常,因为从BaseStepHandler<GlobalOnBoardingStepOneDataModel>,不BaseStepHandler<BaseStepDataModel>GlobalOnBoardingStepOneHandler继承。这可能是.NET泛型最常见的错误。泛型对于类型参数不是协变的。

参见:

C#: cast to generic interface with base type

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

等等

的问题是,你假设,因为从BaseStepDataModelGlobalOnBoardingStepOneDataModel继承,从BaseStepHandler<BaseStepDataModel>GlobalOnBoardingStepOneHandler继承。事实并非如此,所以你不能从一个人投到另一个人。

作为一个例子,考虑以下因素:

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>

+0

我不明白,请解释。 – SexyMF

+0

对于具体类的泛型参数没有任何逆变/协方差支持。也许这是一个错误,但我觉得它更多是一个缺失的功能,或者一个不可能的功能。 –

+0

您认为替代解决方案是什么? – SexyMF

3

问题单独和不同类型这里是你希望 逆变 协方差的具体类型泛型参数。

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

你可以设计这样一个标记接口:

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

+1

这当然假设他只是以协变的方式使用他的'BaseDataModel'。如果他不是,这甚至不会编译。 –

+0

@ChrisShain好吧,但也许解决他的问题会迫使他重构他的代码,所以他避免了这个问题......这取决于他......我想向他展示一种实现他的目标的方式,可悲的是没有人能想象范围和其他问题会发现他... –

+0

我并不是说你错了 - 事实上,当我输入这个信息时,我正在向你投票。我只是指出这不是万能的。 –