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

a.t*_*aby 14 c# generics ienumerable casting

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

IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;
Run Code Online (Sandbox Code Playgroud)

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

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

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

Unable to cast object of type System.Collections.Generic.List1[System.Double] 
to type System.Collections.Generic.IEnumerable1[System.Object].
Run Code Online (Sandbox Code Playgroud)

是什么区别stringdouble和是什么原因导致代码的工作string,但不是double

更新

根据这篇文章,我们可以简单地将一个列表转换为IEnumerable(没有类型参数),因为我只需要迭代项目并将新项目添加到列表中(实际上我根本不需要列出列表中的项目).我决定用这个:

var objects = (IEnumerable)dataModel.Value;
Run Code Online (Sandbox Code Playgroud)

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

The*_*kis 21

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

值类型参数的构造类型是不变的,因为它们对超类型(例如object)的隐式转换是表示变化的,这是由于需要的装箱.这就是为什么IEnumerable<double>不变的原因.

请参阅相关文档:

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

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

var sequence = list.Cast<object>();
Run Code Online (Sandbox Code Playgroud)

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