为什么将数组强制转换为IEnumerable忽略延迟执行?

达里尔

我今天遇到了这个问题,但不了解发生了什么:

enum Foo
{
    Zero,
    One,
    Two
}

void Main()
{
    IEnumerable<Foo> a = new Foo[]{ Foo.Zero, Foo.One, Foo.Two};
    IEnumerable<Foo> b = a.ToList();

    PrintGeneric(a.Cast<int>());
    PrintGeneric(b.Cast<int>());

    Print(a.Cast<int>());
    Print(b.Cast<int>());
}

public static void PrintGeneric<T>(IEnumerable<T> values){
    foreach(T value in values){
        Console.WriteLine(value);
    }
}

public static void Print(IEnumerable values){
    foreach(object value in values){
        Console.WriteLine(value);
    }
}

输出:

0
1
2
0
1
2
Zero
One
Two
0
1
2

我知道Cast()会导致延迟执行,但仅当实际实现的集合是数组时,它看起来像将其强制转换为IEnumerable结果才会丢失。

为什么Print方法中的值枚举会导致将enum其强制转换intList<Foo>集合的,而不是Foo[]

乔恩·斯基特

这是由于优化,不幸的是,在遇到意外的CLR转换时,优化略有中断。

在CLR级别上,存在引用转换-您实际上根本不需要转换每个对象。在C#级别上并非如此,但在CLR级别上却如此。Foo[]int[]

现在,Cast<>包含一个优化说:“如果我已经在处理正确类型的集合,那么我可以只返回相同的引用”-实际上是这样的:

if (source is IEnumerable<T>)
{
    return source;
}

因此a.Cast<int>返回a,这是一个Foo[]当您将其传递给时PrintGeneric这很好,因为Tforeach循环中存在对的隐式转换编译器知道IEnumerator<T>.Currentis的类型T,因此相关的堆栈插槽是type T按类型参数JIT编译的代码在将值视为int而不是时将“做正确的事” Foo

但是,当您将数组作为传递时IEnumerable,的Current属性IEnumerator只是类型object,因此每个值都将被装箱并传递给Console.WriteLine(object)-,而装箱的对象将为类型Foo,而不是int

这是一些示例代码,显示了其中的第一部分-相信您可以通过剩下的一些简单的代码来理解它:

using System;
using System.Linq;

enum Foo { }

class Test
{
    static void Main()
    {
        Foo[] x = new Foo[10];
        // False because the C# compiler is cocky, and "optimizes" it out
        Console.WriteLine(x is int[]);

        // True because when we put a blindfold in front of the compiler,
        // the evaluation is left to the CLR
        Console.WriteLine(((object) x) is int[]);

        // Foo[] and True because Cast returns the same reference back
        Console.WriteLine(x.Cast<int>().GetType());
        Console.WriteLine(ReferenceEquals(x, x.Cast<int>()));
    }
}

如果尝试在两者之间穿梭uint[]您会看到相同的东西int[]

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么将枚举数组强制转换为两种不同的IEnumerable <T>类型?

来自分类Dev

为什么将a从数组强制转换为指针会破坏我的数据?

来自分类Dev

是否将IEnumerable强制转换为IList <TResult>会枚举序列,为什么会首选此序列?

来自分类Dev

是否将IEnumerable强制转换为IList <TResult>会枚举序列,为什么会首选此序列?

来自分类Dev

为什么将值转换为数组?

来自分类Dev

为什么Clang将结构参数强制转换为int

来自分类Dev

为什么将signal()的结果强制转换为(void)?

来自分类Dev

为什么Clang将结构参数强制转换为int

来自分类Dev

为什么将NULL强制转换为结构指针?

来自分类Dev

当将Int64强制转换为Int32时,为什么C#让我溢出而没有任何错误或警告,它如何执行强制转换?

来自分类Dev

为什么需要将IDictionary <T,HashSet <S >>强制转换为IDictionary <T,IEnumerable <S >>?

来自分类Dev

为什么需要将IDictionary <T,HashSet <S >>强制转换为IDictionary <T,IEnumerable <S >>?

来自分类Dev

为什么将char数组强制转换为int指针并使用该指针进行写入会使数据反转?

来自分类Dev

为什么根据我初始化值的方式将值强制转换为IEnumerable <T>会有所不同?

来自分类Dev

将数组转换为IEnumerable <T>

来自分类Dev

无法将数组转换为IEnumerable

来自分类Dev

将IEnumerable <IGrouping <,>>转换为数组

来自分类Dev

将IEnumerable <IGrouping <,>>转换为数组

来自分类Dev

C数组数组:为什么我需要在此处强制转换为const?

来自分类Dev

将IEnumerable <PageData>强制转换为Episerver PageDataCollection

来自分类Dev

将目标强制转换为IEnumerable时,Moqing GetEnumerable失败

来自分类Dev

将IEnumerable <object>强制转换为List <object>

来自分类Dev

将基本类型的列表强制转换为IEnumerable <object>

来自分类Dev

为什么强制转换Object []数组是错误的?

来自分类Dev

为什么将IQueryable强制转换为.toList()以将数据包含到对象DbContext中?

来自分类Dev

为什么初始化指针时必须将数组强制转换为type []?

来自分类Dev

为什么将List <double>显式转换为IEnumerable <object>会引发异常?

来自分类Dev

为什么将'System.Collections.Generic.IEnumerable'转换为System.Collections.Generic.IEnumerable被视为错误

来自分类Dev

为什么我没有收到将指针强制转换为int的警告?

Related 相关文章

  1. 1

    为什么将枚举数组强制转换为两种不同的IEnumerable <T>类型?

  2. 2

    为什么将a从数组强制转换为指针会破坏我的数据?

  3. 3

    是否将IEnumerable强制转换为IList <TResult>会枚举序列,为什么会首选此序列?

  4. 4

    是否将IEnumerable强制转换为IList <TResult>会枚举序列,为什么会首选此序列?

  5. 5

    为什么将值转换为数组?

  6. 6

    为什么Clang将结构参数强制转换为int

  7. 7

    为什么将signal()的结果强制转换为(void)?

  8. 8

    为什么Clang将结构参数强制转换为int

  9. 9

    为什么将NULL强制转换为结构指针?

  10. 10

    当将Int64强制转换为Int32时,为什么C#让我溢出而没有任何错误或警告,它如何执行强制转换?

  11. 11

    为什么需要将IDictionary <T,HashSet <S >>强制转换为IDictionary <T,IEnumerable <S >>?

  12. 12

    为什么需要将IDictionary <T,HashSet <S >>强制转换为IDictionary <T,IEnumerable <S >>?

  13. 13

    为什么将char数组强制转换为int指针并使用该指针进行写入会使数据反转?

  14. 14

    为什么根据我初始化值的方式将值强制转换为IEnumerable <T>会有所不同?

  15. 15

    将数组转换为IEnumerable <T>

  16. 16

    无法将数组转换为IEnumerable

  17. 17

    将IEnumerable <IGrouping <,>>转换为数组

  18. 18

    将IEnumerable <IGrouping <,>>转换为数组

  19. 19

    C数组数组:为什么我需要在此处强制转换为const?

  20. 20

    将IEnumerable <PageData>强制转换为Episerver PageDataCollection

  21. 21

    将目标强制转换为IEnumerable时,Moqing GetEnumerable失败

  22. 22

    将IEnumerable <object>强制转换为List <object>

  23. 23

    将基本类型的列表强制转换为IEnumerable <object>

  24. 24

    为什么强制转换Object []数组是错误的?

  25. 25

    为什么将IQueryable强制转换为.toList()以将数据包含到对象DbContext中?

  26. 26

    为什么初始化指针时必须将数组强制转换为type []?

  27. 27

    为什么将List <double>显式转换为IEnumerable <object>会引发异常?

  28. 28

    为什么将'System.Collections.Generic.IEnumerable'转换为System.Collections.Generic.IEnumerable被视为错误

  29. 29

    为什么我没有收到将指针强制转换为int的警告?

热门标签

归档