如何上传泛型类型参数 [英] How to upcast generic type parameters

查看:111
本文介绍了如何上传泛型类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


GlobalOnBoardingStepOneHandler 继承自 BaseStepHandler< GlobalOnBoardingStepOneDataModel> 解决方案

,而不是 BaseStepHandler< BaseStepDataModel> 。这可能是.NET泛型最常见的错误。泛型对于类型参数不是协变的。



请参阅:

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

等...

问题在于你假设因为 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

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆