【发布时间】:2013-11-24 16:27:38
【问题描述】:
在研究 CLI 的内部时,我注意到类型签名可以指定数组边界(在编译时)。例如,而不是:
Byte[,]
我们可以:
Byte[1...100,1...]
如果我没记错的话,实际上不可能在 C# 或 C++/CLI 中声明像后者这样的类型。此外,ECMA-335 表明:
VES 为每个可区分的数组类型创建一个数组类型。一般来说,数组类型仅通过其元素的类型和排名来区分。
公共语言规范 (CLS) 施加了许多限制,包括:
只有一个项目是一个数组并且数组的元素类型应该是 需要区分重载。
因此,对编译时数组边界的支持似乎出现在 CLI 的最低级别,而不是其他地方。这让我想知道:
在实践中何时会创建/遇到包含此信息的类型签名?是否有 .NET 语言确实 发出这个?编辑:有些语言可能确实通常使用基于一的数组 - 但它们是否将其编码到类型签名中?
如果此信息存在,CLI 实际在何处使用此信息? (当我正在设计 CLI 实现时,我特别感兴趣。)
据我所知,任何数组都是使用newarr 字节码指令创建向量,或者Array.CreateInstance 用于一般情况。这些机制都不接受数组本身的类型签名,因此创建似乎无法使用此信息。
理论上,通过内联高效的机器代码来计算地址,此信息可能有助于优化数组访问。但是,ldelem 和朋友只能访问简单的向量;多维数组访问需要一个方法调用,这让我觉得这样的优化可能不会发生。
我不得不认为这种机制是有目的的,以使其成为国际标准,但我并没有真正看到它。
【问题讨论】:
-
作为评论,这只是我个人的猜想:有些语言允许自定义数组开始索引,而不是 C# 建模的基于 C 的语言。尽管如此,CLI 仍支持那些自定义的起始索引,并且基于 Pascal 的语言(例如 Oxygene 或 A#)的编译器很可能会发出这种数组。实际上可以在 C# 中使用 this overload of
Array.CreateInstance反射创建非零基数组。 -
哦,至少在调用
Array.GetLowerBoundmethod 时,CLI 肯定会使用这些信息。 -
@O.R.Mapper:我感觉可能有一些语言会使用这样的边界。但是,请注意您提到的
Array.CreateInstance重载实际上将边界作为参数,因此 不要使用来自类型签名的信息。同样,Array.GetLowerBound正在访问有关 运行时实例 的信息。我知道可以在 runtime 直接使用非零基数 - 我更关心为什么这些信息可以静态包含在 type signatures 中。
标签: .net arrays type-systems