# Friday, June 29, 2007

I've touched on this before, but I'd like to expound some personal theories (or preferences) on exception handling in C#.  There are plenty of things to debate here, but this is what I believe.

There are a few assumptions I make about code to which these exception handling rules apply, and I'll try to make those assumptions evident as I go along.

  • Method names are verbs.  I'm big on verbs and nouns in code (which, I recently learned, makes me a fan of "Domain Driven Design").
    • If my method is supposed to transfer money from one back account to another, it should be called Transfer
    • If my method can't fulfill it's contract (in the form of it's verb) it should throw an exception.  If Transfer can't transfer, it should throw an exception.  Period.
      • Don't worry about whether the error is really "exceptional".  If it was really exceptional, you wouldn't catch it (see below).
  • Catch only exceptions you know how to handle, and be specific.
    • Don't catch System.Exception.
      • If you don't know ahead of time what the exception is going to be, you don't know how to handle it, and you should send it up the stack.
      • Catching System.Exception means trying to deal with the really exceptional case, which by definition you can't plan for.
  • Write your own application specific Exception classes, and write lots of them
    • Make exceptions as specific as possible
      • if I'm writing Transfer, and there isn't enough money in the source account to fulfill the request, throw an InsufficientFundsException, not ArgumentException or ApplicationException, or InvalidOperationException.
    • Hide implementation specific exceptions by wrapping them in custom exceptions.
      • If you are writing a configuration system, and in your initialization routine you look for an XML config file, and that file isn't there, don't throw FileNotFoundException.  Wrap the FileNotFoundException in your own ConfigurationInitializationException.
        • The consumer of the configuration system doesn't care about your config file, they just care that you failed to initialize.
        • The ConfigurationInitializationException should be part of your contract to the outside world, and they should plan to catch that, not FileNotFoundException.
        • If you change the config system to initialize itself from the database instead of an XML file, and the database isn't there, your consumer doesn't have to worry about DbNotFoundException, just your custom exception according to your contract.
    • Make your custom exceptions part of your contract
      • In Java, you can make that compile-time checkable.
      • In .NET, you can include the exception in your XML documentation using the <exception> element.  It's not enforceable, but at least it's documented.
    • Make sure your custom exceptions are serializable and implement the right constructors
      • VS 2005 has a template that generates good exception classes (type exception->tab)
    • There may be some very specific reasons for catching System.Exception (but I don't really believe that)
      • If you must, never catch Exception without throwing something else.
        • If you don't care if your code failed, why did you write it?  That probably points to a design problem.
      • If you find yourself arguing for catching Exception, you probably have a design problem.
        • There are real reasons for crashing your application.  If nobody knows how to handle an exception, should you really keep going?  Or just take your lumps and quit?
        • If your application writes to the database, and the database isn't there, should you keep logging errors, or just exit the application?  (This depends on how transient the problem is, etc., and I'm probably ratholing here so you get it, right?)

YMMV, but there you go.

Discuss.

Friday, June 29, 2007 11:54:55 AM (Pacific Daylight Time, UTC-07:00)  #    Disclaimer  |  Comments [4]  |