请考虑以下场景:
方法期望将两个索引确定为参数,其中一个索引等于或大于另一个索引,从而使有效范围相互依赖。
例如,获取数组子副本的方法,具有开始和结束索引:
public static T[] Sub<T>(this T[] @this, int start, int end) {
//Somewhere within...
var newLength = end - start;
if (newLength < 0)
//Throw exception because end<start...
}
现在,这是一个(诚然有点无关紧要,但仍然很有趣[恕我直言])问题:
ArgumentOutOfRangeException
定义为:
当参数的值在外部时引发的异常调用方法定义的允许值范围。
哪个有点适合这种情况,有点不适合:
- 该方法定义了"索引 A 必须小于索引 B">,但这定义了
A
和B
之间的关系;不完全是A
和B
的有效范围...... - 最终,在这个例子中,
B
的有效范围由A
定义;而不是(显式地)由方法定义。
另一方面,ArgumentException
定义为:
当其中一个参数提供给 方法无效。
考虑到我关于A
如何定义B
有效范围的论点,实际上完全符合:
- 一个参数
B
在小于A
时无效。
然而,异常(无论哪个)仍然基于索引,如果索引,则直接绑定到有效或无效范围......
所以。。。
是否应该抛出更通用的ArgumentException
,因为索引的组合使它们无效?
是否应该抛出更具体的ArgumentOutOfRangeException
,即使这里的"无效">与例外的预期用途并不完全匹配?
还是应该扔SomethingElseEntirelyException
?
我会选择ArgumentOutOfRangeException
.这与框架中其他地方的其他示例相吻合:
- 如果">startIndex加上长度表示不在此实例中的位置",
string.Substring(int, int)
会抛出AOORE
。 - 如果">sourceIndex小于sourceArray第一维的下限",
Array.Copy(Array, int, Array, int, int)
会抛出AOORE
。 - 如果">日小于 1 或大于一个月中的天数",
DateTime(int, int, int)
会抛出AOORE
。
另一方面,我也应该提供一个反例:
- 如果">偏移量和计数的总和大于缓冲区长度",
Stream.Read(byte[], int, int)
会抛出ArgumentException
。
我不确定为什么最后一个是这样定义的,但我想说该方法根据其他参数和对象状态定义有效值的范围是合理的。不过,我个人会尝试根据早期参数定义特定参数的有效值范围 - 所以如果你Foo(int x, int y)
要求x < y
,那么我会说y
的有效范围是根据x
定义的。