为什么Enumerable.Cast不使用用户定义的强制转换?

hor*_*rgh 12 c# ienumerable casting

说,我们有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 };
    }
}
Run Code Online (Sandbox Code Playgroud)

那么为什么

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
Run Code Online (Sandbox Code Playgroud)

同样的explicit操作.

PS:手动(separetely)投射每个元素

List<B> listB = listA.Select<A, B>(s => s).ToList(); //OK
Run Code Online (Sandbox Code Playgroud)

Dan*_*rth 10

该名称具有Enumerable.Cast误导性,因为它的目的是取消装箱值.它适用于IEnumerable(IEnumerable<T>)产生的IEnumerable<T>.如果您已经拥有了IEnumerable<T> Enumerable.Cast很可能不是您想要使用的方法.

从技术上讲,它正在做这样的事情:

foreach(object obj in value)
    yield return (T)obj;
Run Code Online (Sandbox Code Playgroud)

如果T不是盒装值,这将导致InvalidCastException.

您可以自己测试此行为:

int i = 0;
object o = i;
double d1 = (double)i; // Works.
double d2 = (double)o; // Throws InvalidCastException
Run Code Online (Sandbox Code Playgroud)

您有两种可能的解决方案:

  1. 使用 Select(x => (B)x)
  2. 创建一个Cast适用于IEnumerable<T>而不是一个的扩展方法IEnumerable.

  • @KonstantinVasilcov:`Enumerable.Cast`被定义为`public static IEnumerable <T> Cast <T>(这个IEnumerable值)`.这意味着该方法不知道列表中的类型.你可以自己试试:`List <A> list = ...; IEnumerable values = list; foreach(var a in values)(B)a;`这也会产生这个异常,因为`a`是一个`object`.这正是你使用`Enumerable.Cast`时发生的事情. (3认同)