Conventional wisdom suggests we should only catch the specific exception types we're expecting:
try
{
int.Parse(str); //I am aware of TryParse(), this is just for the sake of example
}
catch (FormatException ex)
{
Console.WriteLine (ex);
}
catch (OverflowException ex)
{
Console.WriteLine (ex);
}
However, sometimes we don't really care which exception happened (as long as it's not fatal), maybe because we just want to let the user know an error occurred. In these cases we can do something like this:
try
{
Foo();
}
catch (Exception ex)
{
if (IsCriticalException(ex))
{
Environment.FailFast("System Error", ex);
}
Console.WriteLine ("Error running Foo: {0}", ex);
}
Where IsCriticalException
can be implemented similarly to System.ClientUtils.IsCriticalException. I am generally in favor of this approach for a couple of reasons:
- Some methods can throw many exception types and it can be cumbersome to catch them all. For example, File.Open can throw nine different types of exceptions.
- Some methods can throw undocumented exceptions. This is either due to lacking documentation, or due to some bug. For example, ICommunicationObject.Close can actually throw
ArgumentException
due to an obscure bug. Some methods cannot even know statically which exceptions could be thrown by them, since they load other modules / plugins dynamically. Supposedly they could wrap all such "external" exceptions with their own known exceptions, but I believe not all of them do.
The critics of this approach argue that a method's exceptions are part of its contract. If an exception is thrown that is not part of this contract, we should assume its state is corrupt. We will have also discovered a bug in the method (one we otherwise would not have spotted since we'd have swallowed the unexpected exception). We could then relay this bug to the framework's developers, and this is a win - especially if those developers are in our company, so we've "helped ourselves" so to speak.
I admit, the critics present valid points, but I feel they are a bit idealistic. Practically, I think generic non-fatal exception catching makes sense in a lot of situations. Am I making sense?
Related reading: