Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Enumerable.Cast does not utilize user-defined casts?

Say, we have 2 classes:

public class A
{
    public int a;
}

public class B
{
    public int b;

    public static implicit operator B(A x)
    {
        return new B { b = x.a };
    }
}

Then why

A a = new A { a = 0 };
B b = a; //OK

List<A> listA = new List<A> { new A { a = 0 } };
List<B> listB = listA.Cast<B>().ToList(); //throws InvalidCastException

The same for explicit operator.

P.S.: casting each element manually (separetely) works

List<B> listB = listA.Select<A, B>(s => s).ToList(); //OK
like image 1000
horgh Avatar asked Sep 17 '12 07:09

horgh


1 Answers

The name of Enumerable.Cast is misleading as its purpose is to unbox values. It works on IEnumerable (not on IEnumerable<T>) to produce an IEnumerable<T>. If you already have an IEnumerable<T> Enumerable.Cast is most likely not the method you want to use.

Technically, it is doing something like this:

foreach(object obj in value)
    yield return (T)obj;

If T is something else than the boxed value, this will lead to an InvalidCastException.

You can test this behaviour yourself:

int i = 0;
object o = i;
double d1 = (double)i; // Works.
double d2 = (double)o; // Throws InvalidCastException

You have two possible solutions:

  1. Use Select(x => (B)x)
  2. Create an extension method Cast that works on an IEnumerable<T> rather than an IEnumerable.
like image 175
Daniel Hilgarth Avatar answered Oct 03 '22 07:10

Daniel Hilgarth