【问题标题】:Why am I getting InvalidCastException?为什么我会收到 InvalidCastException?
【发布时间】:2011-03-15 08:57:37
【问题描述】:

我在c#中有以下代码sn-p

List<int> list = new List<int>() { 1, 23, 5, 3, 423, 3 };
            var query = list.Cast<double>().Select(d => d);
            try
            {
                foreach (var item in query)
                {
                    Console.WriteLine(item);

                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

            }

它编译得很好,但是当我执行这个时,我得到了异常。

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    因为您是从 int 类型转换为 double,所以这不是转换,而是类型转换,这与在一般情况下将 int 转换为 double 时有所不同。

    Cast&lt;T&gt;扩展方法使用IL指令unbox.any

    像这样的 C# 强制转换

    var x = (double)42;
    

    其实是IL指令的结果

    conv.r8 
    

    从根本上将一个类型拆箱为不同类型是错误的,这就是您得到异常的原因。

    This 问题的答案相同,并且还链接到 Eric Lippert 的 blog post

    【讨论】:

    • 感谢您的回复。现在我有一个问题,什么时候使用 Cast 扩展方法。
    【解决方案2】:

    list 包含 ints,您尝试将其转换为 double。将您的查询更改为

    var query = list.Select(d => (double)d);
    

    更新

    这是Enumerable.Cast (.NET 4) 的来源:

    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) { 
        IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
        if (typedSource != null) return typedSource; 
        if (source == null) throw Error.ArgumentNull("source");
        return CastIterator<TResult>(source);
    }
    
    static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
        foreach (object obj in source) yield return (TResult)obj; 
    } 
    

    如您所见,CastIterator 尝试将object(在本例中为装箱的int)转换为double。仅当目标类型与被装箱的原始类型完全相同时,拆箱操作才会成功,因此会引发异常。 This link John Leidegren 提供的详细解释。

    【讨论】:

    • 但我使用的是 Cast 扩展方法。
    • Jon:我没有投反对票,但如果您查看 John 的回答(以及 Lex 的链接帖子),这似乎是不正确的。您会在粘贴的代码中注意到,从IEnumerable&lt;int&gt;IEnumerable&lt;double&gt; 的转换只会作为快速路径进行尝试。实际的错误是因为你不能从object(装箱int)转换为double,这发生在Enumerable返回的CastIterator中。
    • @Porges:谢谢!这应该教会我在喝早咖啡之前写作。更正了答案。
    【解决方案3】:

    .NET Framework 类型转换和 C# 类型转换之间存在差异。他们不一样。将 int 转换为 double 是 C# 语言的一个特性,并且是该语言本身的特性。

    为此,C# 编译器可以使用特殊指令将 int 转换为 double。编译器在编译时知道源类型是“int”,目标类型是“double”,因此可以生成正确的指令。这并不是 .NET Framework 意义上的真正类型转换。

    System.Int32 不能强制转换为 System.Double。 Cast 扩展方法是在不知道源集合和目标集合的确切类型的情况下编译的,因此没有生成用于处理 C# 特定 功能的特殊指令。为 Cast 扩展方法生成的唯一代码是普通的 .NET 类型转换(将类转换为其基类型、转换为对象以及将类型转换为它们实现的接口)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-09
      • 2023-04-05
      • 2016-08-21
      • 2014-07-04
      • 2020-06-06
      • 2018-12-26
      • 2021-03-05
      • 2013-07-13
      相关资源
      最近更新 更多