Home

It's another exceptional post

[Click to print this article]

Eurydice, number two cat

Several things have turned up at work in the past few days, all related to exceptions in .NET. Wow, this blog certainly seems to be turning into a blog about exceptions.

The first one was that, if you are going to create your own exception class hierarchy, you should derive the root of it from Exception and not ApplicationException. It seems that, although ApplicationException used to be the recommended ancestor, and although it is used as so throughout MSDN's documentation, it is no longer. See this thread on Brad Abrams's blog for further information, but the argument goes that exception hierarchies should be broad and shallow; shallow as in not more than two or three classes deep. In essence you should have one ancestor for your hierarchy and then one exception class for every type of error that needs to be reported. The recommendation is to not use error code properties within your exception classes either, but to have one exception class per error code (the archetypical bad boy in this respect is SqlException, of course). Putting ApplicationException as your ancestor adds a new level to your exception hierarchy without giving you any benefit whatsoever.

The second thing that cropped up was a bald reference in MSDN's Design Guidelines for Class Libraries which read, "Use the common constructors [...] when creating exception classes." The common constructors are

public class XxxException : Exception 
{
   public XxxException() {... }
   public XxxException(string message) {... }
   public XxxException(string message, Exception inner) {... }
   public XxxException(SerializationInfo info, StreamingContext context) {...}
}

But there was no reason why. For some reason, I went off on a complete tangent trying to find arcane reasons for this (man, I must have been tired after the clock change on Sunday, or something). You see, my years of using Delphi had taught me that constructors were inherited, so I assumed that a bare XxxException class definition in C# would have these constructors already defined and usable. In Delphi, you define a new exception class hierarchy like this:

type
  MyRootException = class(Exception);
  MyNilParameterException = class(MyRootException);
  MyOutOfBoundsException = class(MyRootException);
  ...

Quick and simple. No messing. No code, per se.

Well, more fool me. I found out that constructors are never inherited in C#. The only constructors you get for a class are the ones you explicitly write for the class. If you don't write any constructors at all then the compiler creates one for you (the one with no parameters), whose implementation is to call the base class' similarly defined constructor (and if the base class doesn't have one then you'll get a compile error).

So, now it's obvious why you should define these constructors. If you don't, they won't be there, and users of your exception class will be expecting them.

And, geez, the errors that creep into your reasoning and your code when you switch from language to language...

The third exceptional item was a discussion we were having about catch blocks. Our code has way too many catch blocks, most of which just log the exception and rethrow it. This tends to means that if an exception is thrown deep in a call stack, every method in the call stack will catch the exception, log it, and then throw it. Our log gets full of lines reporting the same exception for each method as it unwinds the call stack. Some catch blocks don't even rethrow the exception after logging it.

I'm proposing this. We divide up the exceptions into two categories: those exceptions we can catch and actually do something about straight away -- let's call them the recoverable exceptions -- and those exceptions we don't know what to do about because they are totally unforeseen.

An example of a recoverable exception is this one. There's a couple of places where SQL Server might return a lock error as an exception. In that case, we can retry the call to SQL Server again to see if the lock has gone. Of course there is the proviso that we only try again twice, after the third failure we actually assume the issue in not recoverable and allow the exception to escape.

For the non-recoverable exceptions we just let them escape all the way up to the outer method in the call stack for the thread or the appdomain. There they will be logged. My recommendation then is to let them escape, that is rethrow them, or to shut the application down (maybe with some Watson-like "phone home" error reporting first) but it's a difficult decision.

In essence, for some of these unrecoverable exceptions we could recover to a certain extent (shut down the application's engine and then restart it) but we run into the possibility of repeating the situation that caused the exception (can you spell infinite loop?). This is most likely if the exception is thrown due to some internal issue (for example, bad data in a file that's getting transformed for the database).

If the exception was due to some external reason, say the link to the database server going down, we could recover from by going into a loop until the situation resolves itself, and then starting up the engine again.

This stuff isn't easy by all means and deciding which exception is which in the abstract is probably prone to failure. Possibly the best idea is to run the application and hack its environment and/or throw stuff at it until we get an exception. (Examples: unplug the machine from the network, or forcibly terminate a process it's using, or feed it very bad input, or scribble over its files, etc, etc.)

Work out where the exception took place, and why, and then either strengthen the code so that the exception won't get thrown (best idea), or add a catch block in some method to try and recover from the exception (not so good an idea).