When used properly, the structured exception-handling system in .NET can produce efficient, clean, and unobtrusive error handling for your applications. When used improperly, however, this same system can bog down your apps and become a major pain in the neck. So, to keep everyone on the straight and narrow, I present my 10 tips for exceptional exception handling.
1. Use one try and many catches
When placing exception-handling code in your applications, it's generally better to enclose all code that may throw an exception in a single try block and have multiple catch blocks set to trap different expected exceptions. Having all catch statements in a central location increases the readability of your code.
2. Order catch blocks from specific to general
When placing catch blocks in your code that are set to catch different types of exception, always place them in order from most specific to most general. Doing so not only makes it clear that specific exception types will be handled before the more general types, but it also helps other developers reading your code understand what's going on.
3. Always ensure you reach a valid state
The minimum standard for exception handling should be to ensure that your object returns to a valid state after the exception occurs, and a caller should be able to safely assume that there were no side effects from an exception in a method call. Perform any needed cleanup to ensure this valid state in a finally block so that it always takes place.
4. Document what you can throw
In Java, developers must declare that a method they write can throw an exception and explicitly list the exceptions that a caller can expect to have thrown to it. That may seem a bit cumbersome to some developers, but knowing in advance which exceptions a method call can generate allows you to form a specific plan for dealing with each of them, rather than depending on a generic "catch everything" block. Always endeavor to document which exceptions can be thrown from any class or method you create.
5. Throw the closest match
In situations where more than one exception can represent the same error, always throw the exception type that most closely matches the error condition. In the case of a division by zero error, for example, where either an ArithmeticException or a DivideByZero exception could apply, you should throw the latter instead of the former. The main idea is to always communicate the most specific information possible about a given error condition to the code that will catch your exception.
6. Never throw in the course of normal use
Remember that the use of the term exception in programming has to do with the thinking that an exception should represent an exceptional condition. Exceptional conditions, by their very nature, do not normally occur; so your code should not throw exceptions as part of its everyday operations.
Do not throw exceptions to signal commonly occurring events. Consider using alternate methods to communicate to a caller the occurrence of those events and leave the exception throwing for when something truly out of the ordinary happens.
7. Extend the ApplicationException, not the base Exception, class
When creating a custom exception, always extend the ApplicationException class, never the base System.Exception class. Doing so keeps user-defined exceptions in a separate object hierarchy than exceptions that could be thrown by the .NET runtime.
8. Use the inner exception property when rethrowing
Sometimes, you'll need to create and throw a new exception of one type in response to catching an exception of another type in your code. In those cases, you can use one of the overloaded constructors of the base System.Exception class to wrap the exception you caught in the new exception you are throwing. The calling code can then examine the InnerException property of the exception thrown to it to determine the underlying cause of the problem.
9. Do not create lightly
All told, there are well over 100 built-in exception types in the .NET Framework's class library. The children of SystemException represent the largest fraction, covering everything from simple arithmetic errors like division by zero, all the way to an invalid Xpath query.
The point is that a system exception is probably already defined for most errors you'll encounter. If so, you should use that exception rather than create your own. The only time you should consider creating a new exception for an error situation that has a predefined system exception is when the situation is "exceptional" enough that you want the catcher to be able to take a specific action that wouldn't be taken normally.
10. Name appropriately
Any new exception classes you create should have a name ending with the word Exception so there is never any question that the class is an exception class.