Throw Rich Exceptions that are thoroughly informative to allow easy fault diagnosis. This is the tenth in a series of posts on Code Gardening - the practice of making small improvements as you see them while you are working.
System failures are inevitable. When something does go wrong, your code has one final responsibility - to leave enough diagnostic information to allow someone to work out what happened.
Let’s return to the
FindMandatoryCourseByCode() method that we last discussed in the post Boolean Parameters are Evil.
When this exception is thrown, there’s no context given to explain what went wrong - we don’t even get told which course code couldn’t be found. (It’s better than some code, however - at least it’s throwing a useful exception type and not just
Our first improvement is to make the message more informative so that the actual course code is visible as a diagnostic when required.
The course code itself is surrounded by quote (‘) characters so that any leading or trailing whitespace is clearly visible. They also serves to highlight an empty code if one is used.
There is more we can do, however. Every .NET exception has
Data, a dictionary of name/value pairs that is carried along, providing a built-in mechanism for including extra details.
In our case, providing the actual course code opens up other possibilities for handling or reporting on the exception.
At the very least, your outer logging layer should capture the content of this dictionary to ensure the information is not lost.
Aside: For almost every exception the
Data property will be automatically initialized, so you can rely on it being present when you’re creating the exception itself. However, I’ve seen at least one authorative source indicate that some system exceptions (such as
OutOfMemoryException) can show up with
Data set to null. Just to be safe, always check to see if
Data is assigned before doing anything with an exception you’ve caught.
To prevent the exception code from overwhelming the original method, it is often useful to extract it into a private factory method:
This can easily be thrown from wherever required:
Note that we don’t throw the exception within the factory method - instead we throw it from the same place we always used, so that the stack trace takes us directly to the right place.
Idiomatically this can look a little odd because we are so used to seeing new immediately after throw.
As a last point, note that this can be taken another step, adding additional information to other exceptions as they pass through: