数组创建表达式和长尺寸长度

时间:2013-02-15 06:23:23

标签: c# overflowexception

我刚刚阅读了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)?

1 个答案:

答案 0 :(得分: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是生成转换的指令,并在失败时抛出异常。