IanG on Tap

Ian Griffiths in Weblog Form (RSS 2.0)

Blog Navigation

April (2018)

(1 item)

August (2014)

(1 item)

July (2014)

(5 items)

April (2014)

(1 item)

March (2014)

(1 item)

January (2014)

(2 items)

November (2013)

(2 items)

July (2013)

(4 items)

April (2013)

(1 item)

February (2013)

(6 items)

September (2011)

(2 items)

November (2010)

(4 items)

September (2010)

(1 item)

August (2010)

(4 items)

July (2010)

(2 items)

September (2009)

(1 item)

June (2009)

(1 item)

April (2009)

(1 item)

November (2008)

(1 item)

October (2008)

(1 item)

September (2008)

(1 item)

July (2008)

(1 item)

June (2008)

(1 item)

May (2008)

(2 items)

April (2008)

(2 items)

March (2008)

(5 items)

January (2008)

(3 items)

December (2007)

(1 item)

November (2007)

(1 item)

October (2007)

(1 item)

September (2007)

(3 items)

August (2007)

(1 item)

July (2007)

(1 item)

June (2007)

(2 items)

May (2007)

(8 items)

April (2007)

(2 items)

March (2007)

(7 items)

February (2007)

(2 items)

January (2007)

(2 items)

November (2006)

(1 item)

October (2006)

(2 items)

September (2006)

(1 item)

June (2006)

(2 items)

May (2006)

(4 items)

April (2006)

(1 item)

March (2006)

(5 items)

January (2006)

(1 item)

December (2005)

(3 items)

November (2005)

(2 items)

October (2005)

(2 items)

September (2005)

(8 items)

August (2005)

(7 items)

June (2005)

(3 items)

May (2005)

(7 items)

April (2005)

(6 items)

March (2005)

(1 item)

February (2005)

(2 items)

January (2005)

(5 items)

December (2004)

(5 items)

November (2004)

(7 items)

October (2004)

(3 items)

September (2004)

(7 items)

August (2004)

(16 items)

July (2004)

(10 items)

June (2004)

(27 items)

May (2004)

(15 items)

April (2004)

(15 items)

March (2004)

(13 items)

February (2004)

(16 items)

January (2004)

(15 items)

Blog Home

RSS 2.0

Writing

Programming C# 5.0

Programming WPF

Other Sites

Interact Software

When to Catch Exceptions

Monday 16 August, 2004, 08:08 PM

Lamont Harrington recently wrote this:

"For example, when I see code performing some type of data access operation, I expect to see a try...catch... statement around the operation that's performing the task. Just because a particular operation performs successfully after 100 tests, does it mean mean that on the 101st test an unexpected SqlException can't be thrown?"

I think that might be the wrong question. My response would be something like this: sure, of course a SqlException might be thrown, but is this really the right place to catch it?

That's not meant as a rhetorical question, however much it might sound like one. Sometimes the answer will be yes, and sometimes no - it depends on the context.

If the data access code lives inside some service, and is only ever used inside of that service, then often, it will be appropriate to let the exception bubble most of the way up the stack. When writing a service, I usually implement the remote API using the remote facade pattern, because the network interface your service exposes will need to be defined with the kind of coarse-grained approach suitable for a remote API, but your won't want to implement the guts of your service that way. One of the jobs of the facade is to manage errors that occur when processing incoming messages. The details will vary from one case to the next, but it often boils down to something like this:

try
{
    string result = MyBusinessLogic.DoTheRealWork(x, y);
    SendSuccessResponse(result);
}
catch (ApplicationException x)
{
    MyLoggingInfrastructure.DOh(x);
    SendFailureResponse("Internal error processing request");
}

Obviously that's stylised. If you're doing an RPC style of service API, then you would doubtless just return data rather than explicitly generating responses like this. But the general pattern is the same - if something goes wrong deep in the guts of our code, our request is doomed, so we just let the exception bubble up to the top of the tier before dealing with it. (Any necessary tidy up typically goes in a finally block.)

In particular, we do not, as Harrington suggests, have faith that the operation will succeed. Far from it. We simply deal with the failure higher up the stack.

But this is not always appropriate. There are certain boundaries where you will want to map exceptions onto something else. (Either different exceptions, or something else entirely like sending a message somewhere.) In fact the code above is just such an example - the exception has travelled to a boundary where we can't just let it carry on. We need to catch it and map it into some kind of error indication to the client of our service. (That might look like a SOAP fault in a web service, or some other message indicating a problem. In a .NET remoting scenario it might be appropriate to throw an exception, but you would probably want to map it to some documented exception rather than just allowing exceptions from the depths of your code to be thrown straight out at the client.)

In general, some kind of mapping like this will always be required whenever crossing a tier boundary. It may or may not be appropriate for layer boundaries within tiers too.

So would it ever be appropriate to catch an exception right down at the scope at which it would get thrown in the first place, rather than letting it bubble up? I can think of two good reasons you might want to do that: recovery, and mapping.

Sometimes you will be able to recover from the problem - if you have alternate behaviour you can employ to work around the failure, a local catch block is appropriate. However, although those who are new to exceptions often assume that this is what most of their exception handling will consist of, it turns out to be relatively rare. In most cases, if an exception occurs, then even if you anticipate it, your operation will doomed to fail because it depends on the operation that just failed. This means that you'll need to be throwing some kind of exception anyway. The only question is whether you want to throw a different exception from the one that drew your attention to the problem in the first place. This brings us onto the other common reason for catching exceptions at source: mapping.

It is common for certain exception types to make sense only in the context in which they are thrown. For example, the Int32.Parse method will throw a FormatException if the text being parsed is not a valid integer. That exception makes sense at the point at which it is thrown, but in the broader scheme of things it might be indicative of a bad parameter having been passed, so you might want to map it to an ArgumentException. E.g.:

public void Foo(string input)
{
    // Of course as of .NET V2 (aka Whidbey, aka VS.NET 2005)
    // we'd just use int.TryParse instead.
    try
    {
        int i = int.Parse(input);
        SendSuccessResponse(result);
    }
    catch (FormatException)
    {
        throw new ArgumentException("Should be an integer", "input");
    }
}

(Of course this suggests that Foo simply has the wrong signature... But sometimes you just end up being given a string...) It's not uncommon for code not to bother doing this, and for a FormatException to bubble up the stack to a point where it's plain bewildering. So in cases like these it is useful to throw a different exception type just because the original one doesn't really reflect the true nature of the problem.

But in general, these cases where you either need to map the exception to something else, or can handle it in situ are relatively unusual. The vast majority of exception handling code will consist of try ... finally blocks (or using statements) - code that makes sure resources are cleaned up when exceptions occur, without actually attempting to catch the exception. (So if Harrington had said that he expected to see try ... finally blocks or using statements around the code in question, then I would have agreed with him.)

If it's news to you that your finally blocks should be outnumbering your catch blocks by a significant margin, then you're probably doing something wrong. This is not an original thought. You'll find it expressed in the middle of this excellent article (2nd paragraph of the 'Managed Exceptions' section). It also seems to be broadly recognized in the Java world. The main thing to do when an exception is thrown is to clean up your resources, and ensure that you leave everything in a consistent state. You don't need to catch the exception to do that. In fact you shouldn't! finally and using are your friends.

Copyright © 2002-2024, Interact Software Ltd. Content by Ian Griffiths. Please direct all Web site inquiries to webmaster@interact-sw.co.uk