C#Casting Generic Type

我有一个通用接口IConstrained,由通用的Constrained类实现。 当我尝试执行下面的代码时,我得到一个无效的强制转换exception。

IConstrained decimalLimit = new Constrained(1); IConstrained comparableLimit = (IConstrained) decimalLimit; 

如果十进制实现IComparable,为什么不能这样做呢? 这样做的正确方法是什么? 谢谢。

.NET 2.0中的generics类型不协变。 这包括.NET 3.0 / 3.5,因为它们使用相同的2.0运行时。 但是,.NET 4.0将支持协方差 。

将IConstrained 转换为IConstrained 称为协方差。 你不能在C#3中做到这一点。但是,它将在C#4中出现。

Erik Lippert有一系列博客文章,详细介绍了Contravariance和Covariance 。

为了解决这个问题,你必须在使用它时将十进制数转换为IComparable。

这是与C#(以及generics的其他语言)共同的旅行。

在C#中,只能转换为类层次结构中的类(超类,子类)。 但IConstrained既不是超类,也不是IConstrained的子类,即使decimal实现了IComparable。 C#不允许这样做的原因是因为允许它意味着你可以做很糟糕的事情。

有关其原因的详细说明,请查看此类似问题

对于像这样可IConstrained and IConstrained的类,它需要实现两个接口IConstrained and IConstrained

 class A:IConstrained,IConstrained 

它不会自动发生,因为.NET 2.0不实现协方差或逆变。 IConstrained不实现IConstrained 。 是的,这是令人沮丧和反直觉的。 根据我的理解,在C#4.0中实际上会以这种或那种forms支持这种情况。 它被称为协方差或逆变。

编辑:我对Constrained类并不熟悉,但你可以构造一个新的Contrained并传递给它一个小数。 如果它有一个Constrained (T copyFrom)forms的构造函数,那么你可以声明一个新的Constrained并将小数传递给它。 有点像制作副本。

编辑2:在此页面的大约一半处,搜索“2.0”,有一个如何在.NET 2.0中解决此问题的示例: http : //blog.tlk.com/dot-net/2009/c-尖锐-4-协方差和-逆变

这是“怎么做”的答案。

 IList decimalLimit = new List(1); IEnumerable asComparable = decimalLimit.Cast(); IList comparableLimit = asComparable.ToList(); 

对于generics,具有不同类型参数的相同generics类型的两个实例彼此没有直接关系。 换一种说法:

 IConstrained !== IConstrained 

这是一个方差问题。 即使十进制是IComparable,IConstrained 也不是IConstrained 。 我相信在C#4.0下可以实现这种自动转换,并且具有改进的协变性。 但是使用C#3.0或更早版本是不可能的。

阅读反方差和协方差。 意识到C#generics是不变的,你所要求的并不是你想要的。