代码之家  ›  专栏  ›  技术社区  ›  Thomas Levesque

Enumerable.Cast<T>扩展方法无法从int转换为long,为什么[[副本]

  •  16
  • Thomas Levesque  · 技术社区  · 16 年前

    可能重复:
    Puzzling Enumerable.Cast InvalidCastException

    你好

    我只是注意到这件事很奇怪 Enumerable.Cast<T> 扩展方法。。。它似乎不能从你的身上投射出来 int long

    以下代码失败,出现错误 InvalidCastException :

            foreach (var item in Enumerable.Range(0,10).Cast<long>())
            {
                Console.WriteLine(item);
            }
    

    但我认为这条代码是等效的,它确实有效:

            foreach (var item in Enumerable.Range(0,10).Select(i => (long)i))
            {
                Console.WriteLine(item);
            }
    

    有人能解释这种行为吗?我用Reflector查看了Cast方法的代码,但是Reflector不能解释迭代器块,所以很难理解。。。

    3 回复  |  直到 9 年前
        1
  •  16
  •   Rex M    13 年前

    中的相关行 Cast :

     this.<>2__current = (TResult)this.<obj>5__ab;
    

    int foo = 1;
    long bar = Cast<long>(foo); //oh noes!
    
    T Cast<T>(object input)
    {
        return (T)input;
    }
    

    这也失败了。这里的关键是,在施法点,它是一个对象。不是int。这会失败,因为我们只能从对象到 确切类型 我们想要。我们从对象开始,它可以是一个盒装的长,但它不是。这是一个带方框的整数。 Eric Lippert discussed this on his blog :

    在有效的代码中,您不是在处理装箱的int(对象),而是一个int。

        2
  •  10
  •   LukeH    16 年前

    与大多数其他LINQ扩展方法不同, Cast 扩展非泛型 IEnumerable 接口,而不是 IEnumerable<T> .

    int Range 电话被电话号码框住了 铸造 long 失败,因为只能将值解除绑定为完全相同的类型。

    int 价值观:

    foreach (var item in Enumerable.Range(0, 10).Select(i => (long)(object)i))
    {
        Console.WriteLine(item);
    }
    
        3
  •  1
  •   wilson0x4d    16 年前

    问题是CastIterator的MoveNext将当前值装箱,并尝试将其取消装箱到目标类型(装箱的值不是正确的类型),因此在类型检查期间取消装箱失败。

    参考资料:

    http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.unbox_any.aspx

        L_003c: ldarg.0 
        L_003d: ldarg.0 
        L_003e: ldfld class [mscorlib]System.Collections.IEnumerator System.Linq.Enumerable/<CastIterator>d__aa<!TResult>::<>7__wrapac
        L_0043: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
        L_0048: stfld object System.Linq.Enumerable/<CastIterator>d__aa<!TResult>::<obj>5__ab
        L_004d: ldarg.0 
        L_004e: ldarg.0 
        L_004f: ldfld object System.Linq.Enumerable/<CastIterator>d__aa<!TResult>::<obj>5__ab
        L_0054: unbox.any !TResult
    

    解决方法是使用Select()命令