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

[をちょきちょきと切る]

expression-list の次元の長さの式は、左から右に順番に評価されます。各式の評価に続いて、int、uint、long、ulong のいずれかの型への暗黙的な変換 (§6.1) が実行されます。暗黙的な変換が存在するこのリストの最初の型が選択されます。式の評価または後続の暗黙的な変換によって例外が発生した場合、それ以上の式は評価されず、それ以上のステップは実行されません。

興奮して、うーん、まだ見たことがないと思いました。長い次元の長さを試してみましょう。

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 と OutOfMemoryException) が発生するのはなぜですか?

4

1 に答える 1

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

3行目に特に注意してください。そのオペコードは、変換を生成するための命令であり、失敗すると例外をスローします。

于 2013-02-15T06:41:19.647 に答える