Thanks everyone who contributed to my earlier post about living with unchecked exceptions. There were over fifty comments in there that directly or indirectly addressed my questions.

The major takeaway here is: exceptions are a bit of a mess in C#. The language semantics and the organization (or lack thereof) of the exception hierarchy makes it hard to know what exceptions you should be catching and which you should be letting go. A lot of people left a lot of great comments but the one that resonated most strongly with me was

I think the whole notion of “handling” exceptions is a bit of a fool’s game. I can probably count on the fingers of one hand the times where I’ve been able to catch a specific exception and then do something intelligent with it. 99% of the time you should either catch everything or catch nothing. When an exception of any type occurs, rewind to a stable state and then either abort or continue.

That’s harsh but I think fair.

This comment suggests that Pokemon handling — gotta catch ’em all! — is the way to go. I was surprised that almost a third of commenters expressed some support for catch(Exception) as this has historically been described as a bad practice by Microsoft. C# was, as I often say, designed to be a “pit of success” language, where the right thing and the easy thing are the same. That noble goal seems to have not been met here; if catch(Exception) is both the wrong thing to do and the easy thing to do, that’s because the right thing to do is too hard.

The majority of commenters said they had fixed bugs caused by failing to catch a specific exception, though that ranged in a spectrum from “one or two” to “rarely”, to “often”.

A third said that they used MSDN and other forms of documentation (including XML doc comments) to determine what exceptions ought to be caught. MSDN came in for both praise and criticism here; some parts of it are excellent, some are unclear. Third party library documentation came in for a thorough drubbing; no one believes it.

A quarter said that they used some kind of trial-and-error — debugging, testing, reading log files, getting crash dumps — to figure out what exceptions needed to be handled.

Several commenters said that they used decompilers to check what exceptions a library method could throw. And several more expressed the desire for a static analysis tool that would assist them when calling code that could throw an exception.

Again, the frustration was summed up by a comment:

Every try/catch block is an exercise in frustration because you ever know if you’ve caught the right types until it blows up in production.

Quite a few commenters noted that the exception catching system treats the type of the exception as the most important information about it, but a type alone is not enough information to make a good judgment about how to handle an exception.

I asked whether consistency was important. That is, whether seeing that 9 times out of 10 that Frob() is called, it is wrapped in a try{...}catch(FooException) , is good evidence that your next call to Frob() should similarly be wrapped. Opinions varied widely. The responses were pretty evenly distributed across a spectrum that went

absolutely not

probably not but at least give it some thought

it’s hard to say, I’d take it on a case by case basis

probably yes, follow the pattern unless there is good reason to deviate

absolutely yes

And a great many people pointed out that if nine times out of ten a method call is in a block that handles a specific exception then the method in question might better be refactored into a helper method that did the catch for you.

Thanks again all, this was very helpful!