【问题标题】:Arrays have direct support in the CLR数组在 CLR 中有直接支持
【发布时间】:2013-10-31 10:28:14
【问题描述】:

在 Jon Skeet 的“深入 C#”中,我正在阅读(第 511 页):

所有数组都派生自 System.Array,它们是在 CLR 中直接支持的唯一集合(我的重点)。

我想知道这究竟意味着什么,尤其是与不支持此功能的类型有关。 所有没有这种支持的类型都是由 CLR 在解释 IL 时所做的类型组装而成的吗? CLR 是否“不知道”不具有此支持的类型?

同样在第 1 页。全书512篇:

C# 编译器以多种方式内置了对数组的支持。

这在某种程度上与 Array 类型在 CLR 中的直接支持有关,还是这两个完全不同的东西?

【问题讨论】:

  • 当斯基特先生本人可能提供更好的答案时,尝试回答似乎很愚蠢...... :)
  • 看看List of CIL instructions。有很多操作码处理数组,但没有一个处理其他集合。

标签: c# .net arrays clr il


【解决方案1】:

如上所述,数组存在于 CLR 的深处。有与它们交互的 IL 指令 (ldelem.* / stelem.*)。它们早于泛型,但允许根据需要创建不同类型的数组。这不是其他集合类型的情况 - 例如,List<T> 是一个存在于数组顶部的包装器。 CLR 不需要List<T> 的任何特殊知识 - 只需常规 IL 即可访问现有数组的内容或分配新数组。集合的另一种主要形式是链表(和类似的;树等)——但同样,它们不需要特殊支持——它们只是通过引用连接在一起的对象。

【讨论】:

    【解决方案2】:

    是的,编译器、抖动和 CLR 的三重奏有很多内置的数组知识。这对于任何语言运行时都是相当重要的,它不能忽略处理器的功能。为了使代码高效运行,它必须映射到处理器可以做的事情。

    这不是很多,处理器是相当简单的设备。它们没有为您喜欢在程序中使用的那种数据结构提供真正的支持。语言和运行时的设计方式显示了许多底层处理器实现细节。

    例如,堆栈的概念无处不在。处理器可以通过其堆栈指针直接访问的少量内存。这就是为什么 C# 语言和几乎所有语言一样,在方法中具有局部变量的概念。这是一个将存储在堆栈中的变量。处理器还强烈支持使用返回单个值的参数调用方法的概念,这在任何语言中都是通用的。为堆栈分配的少量内存为该站点命名。

    值类型是底层处理器细节的另一个 .NET 示例。它们直接映射到处理器在处理值时擅长的领域。例如,一个 int 直接映射到处理器寄存器。 Float 和 double 直接映射到处理器存储这些值并使用这两种类型执行浮点指令的能力。

    数组是处理器可以支持的唯一且唯一的数据结构。很简单,一块内存,带有访问该内存的指针。 非常在 .NET 中进行了高度优化,以使其尽可能高效。特别向“向量”致敬,这是一种经过特殊处理的数组类型。起始索引为 0 的一维数组,该数组类型直接映射到处理器支持。你会在 C# 中获得一个带有 type[] 声明的向量。您还可以从中看到数组限制,.NET 使创建一个起始索引不为 0 的数组变得非常困难。出于一个很好的理由,索引这样的数组是昂贵的,因为它需要额外的减法来映射内存块的索引。数组索引检查是另一个重要的优化目标,边界检查是昂贵的。 jitter 内置了很多智能,可以识别循环永远不能越界索引数组,从而完全消除索引检查。

    任何数据结构都需要建立在只支持裸阵列的处理器之上。这就是为什么您发现在 .NET 集合类中完成了该操作。没有来自 CLR 或抖动的额外帮助,因为他们几乎无法使其更快。这也是这些集合类都构建在向量数组之上的原因。像 List 一样,根本不是一个类似于您在数据算法教科书中看到的那种列表,实际上是一个数组。或者 Dictionary,一个数组的对立面,但仍然用它们来实现。

    【讨论】:

    • 感谢您的详尽回答。使概念更加清晰。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多