Consider the following scenario:
A method expects two indexes to be determined as parameters, and one of them to be equal to or greater than the other, making the valid range interdependent.
For example, a method to get a sub-copy of an array, with begin and end indexes:
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...
}
Now, here is the (admittedly kind of irrelevant, but still interesting [IMHO]) problem:
ArgumentOutOfRangeException
is defined as:
The exception that is thrown when the value of an argument is outside the allowable range of values as defined by the invoked method.
Which kinda fits the scenario, and kinda doesn't:
A
and B
; not exactly the valid range of A
and B
...B
is defined by A
; not (explicitly) by the method.On the other hand, ArgumentException
is defined as:
The exception that is thrown when one of the arguments provided to a method is not valid.
Which, given consideration to my argument regarding how the valid range of B
is defined by A
, actually fits perfectly:
B
, is invalid when it's less than A
.And yet, the exception (regardless of which) is still based on an index, and directly tied to valid or invalid ranges if indexing...
So...
Should the more general ArgumentException
be thrown, since it's the combination of the indexes that makes them invalid?
Should the more specific ArgumentOutOfRangeException
be thrown, even though the "invalidity" here doesn't(?) quite match the intended use of the exception?
Or should SomethingElseEntirelyException
be thrown?
I'd go with ArgumentOutOfRangeException
. That fits in with other examples elsewhere in the framework:
string.Substring(int, int)
throws AOORE
if "startIndex plus length indicates a position not within this instance."Array.Copy(Array, int, Array, int, int)
throws AOORE
if "sourceIndex is less than the lower bound of the first dimension of sourceArray."DateTime(int, int, int)
throws AOORE
if "day is less than 1 or greater than the number of days in month."On the other hand, I should offer a counter-example too:
Stream.Read(byte[], int, int)
throws ArgumentException
if "The sum of offset and count is larger than the buffer length."I'm not sure why the last one was defined that way, but I'd say it's reasonably for the method to define the range of valid values in terms of other parameters and the state of the object. I would personally try to define the range of valid values of a particular parameter in terms of earlier parameters though - so if you have Foo(int x, int y)
with the requirement that x < y
, then I'd say that y
's valid range is defined in terms of x
.
See more on this question at Stackoverflow