配列の最大要素数

C#の仕様書(ECMA-334)によると、配列宣言時に指定する要素数にはulong型を指定できる。
よって、次のコードは有効なはず。

byte[] bs = new byte[ulong.MaxValue];

実際、この段階ではエラーは起きない。
しかし、このバイト列を操作しようとすると算術結果がオーバーフローしたと言われる。

Console.WriteLine(bs.Length); // OverflowException

ということは、配列のインスタンスは宣言時には生成されず何かしらの操作をしたときに初めて生成されるっぽい?
Array.LongLengthでlong型が返ってくるのでlong型なら何も問題ないはず!!1と思いきや、これもオーバーフローになる。

byte[] bs = new byte[long.MaxValue];
Console.WriteLine(bs.LongLength);

uintでもオーバーフロー。
じゃあint型の場合はというとこれはオーバーフローにはならない。が、空きメモリ量によってはOutOfMemoryExceptionがスローされる。

byte[] bs = new byte[int.MaxValue];
Console.WriteLine(bs.LongLength); // OutOfMemoryException

ちなみにSSCLIのソースコードを見ると、Arrayクラスの要素数はint型で管理されているので、CLRもこの通り実装されているのであれば配列の最大要素数はやはりint.MaxValueになる。
さらにint型で2次元の場合はというと、なぜかこれもオーバーフローにはならない。

byte[,] bs = new byte[int.MaxValue, int.MaxValue];
Console.WriteLine(bs.LongLength); // OutOfMemoryException

つまりArray.LongLengthがlong型なのは、多次元配列の時には総要素数がint型の最大値を超える可能性があるからということなのだろう。じゃあ指定次元の要素数を取ってくるArray.GetLongLengthメソッドは何でlong型を返すの?という話になるが……。


これには何か理由があるのだろうか。int型以外でも0以上int型の最大値以下の範囲ならキャスト無しで使えるということぐらいしかメリットがないが、それならint型に限定した方が安全じゃなかろうか。


例えば2GB以上のファイルをバイト列としてすべて読み込むという頭のおかしいことをするときは、2GBごとに区切って複数の配列に分ける必要があるってことか。