a.toraby February 2016

Why does the explicit conversion of List<double> to IEnumerable<object> throw an exception?

According to this MSDN reference IEnumerable is covariant and this is possible to implicitly cast a list of objects to an enumerable:

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

In my own code i have written a line of code that works perfect when item type of the list is class Point (Point is a simple class with three properties double x,y,z):

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

But the above code returns the following exception when item type of the list is double:

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

What is the difference between string and double and what causes the code to work with string but not with double?

Update

According to this post we could simply cast a list to IEnumerable (without type argument) so as I only need to iterate over items and add new items to the list ( Actually I do not need to cast items of the list, at all). I decided to use this one:

var objects = (IEnumerable)dataModel.Value;

But if you need to cast items of the list to object and use them, the answer from Theodoros is the solution you most follow.

Answers


Theodoros Chatzigiannakis February 2016

Constructed types of variant interfaces (such as IEnumerable<out T>) are variant only for reference type arguments, because their implicit conversion to a supertype (such as object) is a non-representation-changing conversion. This is why IEnumerable<string> is covariant.

Constructed types for value type arguments are invariant, because their implicit conversion to a supertype (such as object) is representation-changing, due to the boxing that's required. This is why IEnumerable<double> is invariant.

See the relevant documentation:

Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.

A possible workaround is to use LINQ cast:

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

This will first check whether the source is assignment-compatible to the IEnumerable<TResult> that you are trying to cast it to.

Post Status

Asked in February 2016
Viewed 3,217 times
Voted 7
Answered 1 times

Search




Leave an answer