【问题标题】:Why Enumerable.Cast does not utilize user-defined casts?为什么 Enumerable.Cast 不使用用户定义的强制转换?
【发布时间】:2012-09-17 07:49:39
【问题描述】:

说,我们有 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

【问题讨论】:

    标签: c# casting ienumerable


    【解决方案1】:

    Enumerable.Cast 的名称具有误导性,因为它的目的是拆箱值。它适用于IEnumerable不是IEnumerable&lt;T&gt;上)产生IEnumerable&lt;T&gt;。如果您已经有IEnumerable&lt;T&gt; 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
    

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

    1. 使用Select(x =&gt; (B)x)
    2. 创建一个扩展方法Cast,它适用于IEnumerable&lt;T&gt;,而不是IEnumerable

    【讨论】:

    • 那么,它失败是因为它试图将object 转换为B,而我定义了从AB 的转换?
    • 它失败了,因为它首先需要将object 拆箱为A,然后进行演员表。像(B)(A)o 这样的东西。您也许可以定义一个适用于 object 而不是 A 的强制转换运算符,但这没有意义,因为大多数 object 实例是不可转换的。
    • 但它是List&lt;T&gt;,其中TA。这不是ArrayListList&lt;object&gt;。为什么会出现这种装箱/拆箱问题?
    • @KonstantinVasilcov: Enumerable.Cast 定义为 public static IEnumerable&lt;T&gt; Cast&lt;T&gt;(this IEnumerable value)。这意味着该方法对列表中的类型一无所知。你可以自己试试:List&lt;A&gt; list = ...; IEnumerable values = list; foreach(var a in values) (B)a; 这也会产生这个异常,因为a 是一个object。这正是您使用 Enumerable.Cast 时发生的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 2012-09-04
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    相关资源
    最近更新 更多