问题
I was just reading the C# specification and the part on array creation expressions. In the specification it says:
array-creation-expression:
new non-array-type [ expression-list ] rank-specifiersopt array-initializeropt
new array-type array-initializer
new rank-specifier array-initializer
[snip]
The dimension length expressions of the expression-list are evaluated in order, from left to right. Following evaluation of each expression, an implicit conversion (§6.1) to one of the following types is performed: int, uint, long, ulong. The first type in this list for which an implicit conversion exists is chosen. If evaluation of an expression or the subsequent implicit conversion causes an exception, then no further expressions are evaluated and no further steps are executed.
Excited, I thought hmm I don't think I've seen that yet, let's try a long dimension length:
bool[] bb = new bool[2L + Int32.MaxValue];
bb[int.MaxValue + 1L] = true;
Visual Studio says while pointing to the first line:
Unhandled Exception: System.OverflowException: Arithmetic operation resulted in an overflow.
Note this is NOT an "OutOfMemoryException". If I change my array creation expression and make it a little smaller:
bool[] bb = new bool[Int32.MaxValue];
This time I get an "OutOfMemoryException". I know about the whole "no object can be larger than 2GB" restriction from the CLR. My question is why am I getting a very different exception (OverflowException vs OutOfMemoryException) when the length is no longer convertible to Int32?
回答1:
The compiler can infer a larger integral type based upon the inputs to the dimensions calculation, but that does not mean the length of the array can exceed the limit. The compiler is basically converting the value to a native integer in a checked context, using an op code that will throw the overflow. This is to prevent the value from wrapping or otherwise allowing a negative number as the dimension.
As an example, note the array declaration here:
var array = new int[2L + int.MaxValue];
And the resultant 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
Pay particular attention to the third line. That op code is the instruction to produce the conversion and throws the exception upon failure.
来源:https://stackoverflow.com/questions/14889333/array-creation-expressions-and-long-dimension-lengths