【问题标题】:.Cast<T> extension method always throws InvalidCastException - How are you supposed to use this method?.Cast<T> 扩展方法总是抛出 InvalidCastException - 你应该如何使用这个方法?
【发布时间】:2017-03-04 14:19:14
【问题描述】:

有几次我对.Cast&lt;T&gt; LINQ 扩展方法感到好奇。我对自己说“这听起来正是我在这种情况下所需要的”,但每当我尝试使用它时,我总是最终得到一个InvalidCaseException。我从来没有成功地使用过这种方法。这是检查异常的示例行:

Enumerable.Range(0,10).Cast<float>().ForEach(Console.Out.WriteLine);

int 转换为float 没有任何争议,那么为什么这种方法拒绝这样做呢?我可以通过简单地将.Cast&lt;float&gt; 替换为.Select(x =&gt; (float)x) 来解决此问题并获得所需的效果

Enumerable.Range(0, 10).Select(x => (float)x).ForEach(Console.Out.WriteLine);

这不是太麻烦,但我还是不明白为什么Cast&lt;float&gt; 方法不能为我完成这项工作。

简而言之:你如何使用.Cast&lt;T&gt;扩展方法?

这与问题无关,但以防万一有人想知道,我在上面的代码 sn-ps 中使用了自定义 ForEach 扩展方法(标准方法仅适用于列表):

static class Extensions
{
    public static void ForEach<T>(this IEnumerable<T> x, Action<T> l)
    {
        foreach (var xs in x) l(xs);
    }
}

【问题讨论】:

标签: c# linq exception casting extension-methods


【解决方案1】:

如果你查看ReferenceSource 获取Cast&lt;TResult&gt;method 的源代码,你会看到最后调用了CastIterator&lt;TResult&gt; 方法,类似于:

static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
    foreach (object obj in source) yield return (TResult)obj;
}

如您所见,C# 尝试从 boxed 对象强制转换为 TResult,这是异常的原因。如果您想模仿问题,请尝试以下操作:

int a = 5;
object o = a;
float f = (float)o;

【讨论】:

    【解决方案2】:

    当你写下以下内容时:

    int a = GetInt();
    var b = (float)a;
    

    你实际上并没有铸造价值。你正在转换它。 C# 只是为您提供了很好的语法。这里生成的 IL 是conv.r4,它将栈顶的值转换为浮点数。

    Enumerable.Cast&lt;T&gt; 实际上是在执行强制转换,并没有得到语法糖的精妙之处。

    如果你要写:

    Enumerable.Range(0,10).Cast<object>().ForEach(Console.Out.WriteLine);
    

    你会没事的,因为整数可转换为对象的。

    【讨论】:

    • 我认为需要更多细节。铸造和转换有什么区别?为什么它不能总是转换?为什么无法创建像您期望的那样工作的 Cast 扩展程序(或者如果可能,如何?)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 2017-06-01
    • 1970-01-01
    • 2014-06-07
    • 2011-10-01
    • 2010-12-26
    • 2011-01-25
    相关资源
    最近更新 更多