I find myself writing some methods where there is a code path that should never happen. Here is a simplified example:
double Foo(double x) {
int maxInput = 100000;
double castMaxInput = (double)maxInput;
if (x < 0 || x > castMaxInput || double.IsNaN(x)) {
return double.NaN;
}
double r = 0;
for (double boundary = 1; boundary<=castMaxInput; boundary++) {
if (x <= boundary) {
r += boundary * (x + 1 - boundary);
return r;
}
else {
r += boundary;
}
}
// we should never get here.
throw new SomeException();
}
The exception that would make the most sense here is something like
TheAuthorOfThisMethodScrewedUpException()
Because that's what is going on if we reach the end of the for loop. Unfortunately, with the method structured as above, the compiler does not appear to be smart enough to figure out that the code after the for loop should never happen. So you can't just have nothing there, or the compiler will complain that "not all code paths return a value". Yes, I could put in return double.NaN
after the loop in addition to before it. But that would disguise the source of the problem.
My question is – is there an exception that would be appropriate?
For example: public int calculateFactorial(int n) { if (n < 0) throw new IllegalArgumentException("n must be positive"); if (n >= 60) throw new IllegalArgumentException("n must be < 60"); ... }
Exceptions should be used for exceptional situations outside of the normal logic of a program. In the example program an out of range value is likely to be fairly common and should be dealt with using normal if-else type logic.
Exceptions are used to indicate that an error has occurred while running the program. Exception objects that describe an error are created and then thrown with the throw keyword. The runtime then searches for the most compatible exception handler.
When an exception is thrown using the throw keyword, the flow of execution of the program is stopped and the control is transferred to the nearest enclosing try-catch block that matches the type of exception thrown. If no such match is found, the default exception handler terminates the program.
I use the InvalidOperationException
class for that. It means that the application has reached a state it should not be in.
throw new InvalidOperationException("Invalid state.");
You can also Debug.Assert
that something is true, or simply Debug.Fail
when execution reaches a particular point.
Debug.Fail("This should never happen!");
But debugging asserts/fails don't work in release mode, only when the DEBUG
conditional is defined. Depends on your requirements whether that's desirable.
As @AlexD correctly points out, there's also the Trace
class with its corresponding Assert
and Fail
methods, that will work at run-time to help isolate and fix problems without disturbing a running system, when the TRACE
conditional is defined (is set by default in the Project Properties Build tab).
By the way, to answer the question in the title: you can create your own exceptions if you want.
[Serializable]
public class TheAuthorOfThisMethodScrewedUpException : InvalidOperationException
{
private const string DefaultMessage = "The author of this method screwed up!";
public TheAuthorOfThisMethodScrewedUpException()
: this(DefaultMessage, null)
{ }
public TheAuthorOfThisMethodScrewedUpException(Exception inner)
: base(DefaultMessage, inner)
{ }
public TheAuthorOfThisMethodScrewedUpException(string message)
: this(message, null)
{ }
public TheAuthorOfThisMethodScrewedUpException(string message, Exception inner)
: base(message, inner)
{ }
protected TheAuthorOfThisMethodScrewedUpException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context)
{ }
}
And throw it at people.
throw new TheAuthorOfThisMethodScrewedUpException();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With