为什么将List <double>显式转换为IEnumerable <object>会抛出异常?

时间:2016-02-08 09:57:58

标签: c# generics casting ienumerable

根据这个MSDN reference IEnumerable是协变的,这可以隐式地将对象列表强制转换为可枚举的对象:

IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;

在我自己的代码中,我编写了一行代码,当列表的项类型为类Point时,它是完美的(Point是一个简单的类,有三个属性double x,y,z):

var objects = (IEnumerable<object>)dataModel.Value;
// here property Value is a list that could be of any type. 

但是当列表的项类型为double时,上面的代码会返回以下异常:

Unable to cast object of type System.Collections.Generic.List1[System.Double] 
to type System.Collections.Generic.IEnumerable1[System.Object].

stringdouble之间的区别是什么导致代码与string一起使用而不是与double一起使用?

更新

根据this post我们可以简单地将列表转换为IEnumerable(没有类型参数),因此我只需要遍历项目并将新项目添加到列表中(实际上我不需要根本列出的列表项目。我决定使用这个:

var objects = (IEnumerable)dataModel.Value;

但是如果您需要将列表中的项目投射到object并使用它们,那么Theodoros的答案就是您最常遵循的解决方案。

1 个答案:

答案 0 :(得分:21)

变体接口的构造类型(例如IEnumerable<out T>)仅对于引用类型参数是变体,因为它们对超类型(例如object)的隐式转换是非表示变化的转换。这就是IEnumerable<string>协变的原因。

值类型参数的构造类型是不变的,因为由于the boxing that's required,它们对超类型(例如object)的隐式转换是表示更改的。这就是IEnumerable<double>不变的原因。

请参阅relevant documentation

  

差异仅适用于参考类型;如果为变量类型参数指定值类型,则该类型参数对于生成的构造类型是不变的。

可能的解决方法是使用LINQ强制转换:

var sequence = list.Cast<object>();

这将首先检查源是否与您尝试将其转换为IEnumerable<TResult>的分配兼容。