Подтвердить что ты не робот

Почему Enumerable.Cast не использует пользовательские приведения?

Скажем, у нас есть 2 класса:

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 };
    }
}

Тогда почему

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

То же самое для оператора explicit.

P.S.: литье каждого элемента вручную (отдельно) работает

List<B> listB = listA.Select<A, B>(s => s).ToList(); //OK
4b9b3361

Ответ 1

Имя Enumerable.Cast вводит в заблуждение, поскольку его целью является удаление значений. Он работает на IEnumerable (не на IEnumerable<T>), чтобы создать IEnumerable<T>. Если у вас уже есть IEnumerable<T> Enumerable.Cast, скорее всего, не метод, который вы хотите использовать.

Технически, он делает что-то вроде этого:

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

Если T - это нечто иное, чем значение в коробке, это приведет к InvalidCastException.

Вы можете проверить это поведение самостоятельно:

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

У вас есть два возможных решения:

  • Используйте Select(x => (B)x)
  • Создайте метод расширения Cast, который работает на IEnumerable<T>, а не на IEnumerable.