2013-02-15 64 views
3

我刚刚阅读C#规范和数组创建表达式部分。在本说明书中它表示:数组创建表达式和长维长度

array-creation-expression: 
new non-array-type [ expression-list ] rank-specifiersopt array-initializeropt 
new array-type array-initializer 
new rank-specifier array-initializer 

[剪断]

表达式列表的尺寸长度表达式进行求值 在顺序,从左到右。在对每个表达式进行评估后, 隐式转换(第6.1节)为以下类型之一,执行的操作如下: :int,uint,long,ulong。这个列表中的第一个类型为 ,其中存在隐式转换。如果 表达式的评估或随后的隐式转换导致异常,则 则不会评估其他表达式,并且不会执行进一步的步骤 。

兴奋,我想嗯,我不认为我已经看到的是,让我们尝试的长尺寸长度:

bool[] bb = new bool[2L + Int32.MaxValue]; 
bb[int.MaxValue + 1L] = true; 

Visual Studio中说,一边指着第一行:

未处理的异常:System.OverflowException:算术运算导致溢出。

请注意,这不是“OutOfMemoryException”。如果我改变我的数组创建表达式,使之变小一点:

bool[] bb = new bool[Int32.MaxValue]; 

这一次,我得到一个“OutOfMemoryException异常”。我知道CLR的整个“没有任何对象可能大于2GB”限制。我的问题是为什么当长度不再可转换为Int32时,我得到了一个非常不同的异常(OverflowException vs OutOfMemoryException)?

回答

4

编译器可以基于尺寸计算的输入推断出更大的整数类型,但这并不意味着阵列的长度可能会超出限制。编译器基本上是在检查的上下文中将该值转换为本地整数,并使用会引发溢出的操作码。这是为了防止该值包装或以其他方式允许负数作为维度。

作为一个例子,说明此处的数组声明:

var array = new int[2L + int.MaxValue]; 

并将所得IL

IL_0001: ldc.i4  01 00 00 80 
IL_0006: conv.u8  
IL_0007: conv.ovf.i 
IL_0008: newarr  System.Int32 
IL_000D: stloc.0  // array 

要特别注意第三行。 op code是产生转换并在失败时抛出异常的指令。