2013-02-15 3 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». Я знаю о том, что ограничение «нет объекта может быть больше 2 ГБ» из CLR. Мой вопрос в том, почему я получаю совсем другое исключение (OverflowException vs OutOfMemoryException), когда длина больше не конвертируется в Int32?

ответ

4

Компилятор может вывести более крупный интегральный тип на основе входных данных для расчета размеров, но это не означает, что длина массива может превышать лимит. Компилятор в основном преобразует значение в собственное целое в проверенном контексте, используя код op, который будет вызывать переполнение. Это делается для того, чтобы предотвратить перенос значения или иначе разрешить отрицательное число в качестве измерения.

В качестве примера отметит объявление массива здесь:

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 является инструкцией для преобразования и выдает исключение при сбое.