为什么负数数组大小会抛出OverflowException异常?

6
在编写可以简化为以下代码的代码后:
var size=-1;
var arr=new byte[size];

我很惊讶它抛出了OverflowExceptionOverflowException的文档说明如下:

当在检查的上下文中进行算术、转换或类型转换操作导致溢出时抛出的异常。

我无法理解为什么为数组长度提供负数大小符合此异常的描述,因此深入研究后发现这确实是指定的行为:

维度长度的计算值按以下方式进行验证。如果一个或多个值小于零,则会抛出System.OverflowException,并且不再执行其他步骤。

我想知道为什么选择了OverflowException。如果你问我,这很误导人。这至少让我调查了5分钟(不算我在这里的思考)。有人能解释一下这个(在我看来)奇怪的设计决定吗?

对我来说,抛出这个异常似乎是合理的。 - cjk
这怎么可能是任何类型的溢出? - spender
3个回答

8
这几乎可以确定是一种优化。.NET框架代码非常重视检查参数,以便让程序员陷入成功的坑中。但这并不是免费的。成本相当微小,许多类方法需要比用于检查的机器周期更多的时间。
但数组是特殊的。它们是框架中非常核心的数据结构。几乎每个集合类都是建立在它们之上的。任何放置在Array类中的开销直接影响到很多依赖它的代码的效率。避免检查是可以的,因为当内部代码需要将值转换为无符号时,它会被隐式检查。而且它很少会引发异常。因此,检查两次并不完全值得更好的异常消息。

5
在文档中,OverflowException 基本上将溢出定义为以下情况:

产生超出数据类型范围的结果

在这种情况下,负值在数组大小(或任何大小)的有效范围之外。
我可以理解 ArgumentOutOfRangeException 在某些方面可能更好,但是在数组定义中没有涉及到参数(因为它不是方法),所以也不是完美的选择。

1

可能是因为该大小是无符号整数。它以二进制补码形式存储-1,当被视为无符号整数时,它是可以存储的最大正整数。如果此数字大于数组可能的大小,则会发生溢出。

警告:这只是纯粹的猜测。


在.NET中,数组大小存储为Int32而不是无符号整数。我相信这样做是为了保持数组的CLS兼容性。 - Reed Copsey
我最初也是这么想的,但规格说明非常明确,是负大小导致了这个异常。 - spender

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接