Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 485
a.toraby Avatar asked Feb 08 '16 09:02

a.toraby


People also ask

Can we convert IEnumerable to list?

In C#, an IEnumerable can be converted to a List through the following lines of code: IEnumerable enumerable = Enumerable. Range(1, 300); List asList = enumerable. ToList();

What is IEnumerable and what significance does it hold?

IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. It is the base interface for all non-generic collections that can be enumerated. This works for read-only access to a collection that implements that IEnumerable can be used with a foreach statement.

What is IEnumerable string in C#?

IEnumerable in C# is an interface that defines one method, GetEnumerator which returns an IEnumerator interface. This allows readonly access to a collection then a collection that implements IEnumerable can be used with a for-each statement.


1 Answers

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.

  • If it is assignment-compatible (as is the case for T being string, for example), it will return the initial source directly (which is the ideal case, performance-wise).
  • If it isn't assignment-compatible (as you have found out is the case for T being double, for example), it will create a projection that attempts the conversion manually for each individual element.
like image 155
Theodoros Chatzigiannakis Avatar answered Oct 13 '22 12:10

Theodoros Chatzigiannakis