Rule "CA1031: Do not catch general exception types" is utterly useless. (not it's intent per se, but it's implementation and description)
In this specific case it may be feasible to catch the more specific IOException
as it covers "most" of the exceptions the StreamReader
constructor is documented to throw.
(oh wait, and then you also need to factor in all the stuff that could be thrown by ReadToEnd
)
(oh, wait, maybe it's a legitimate exception catch case to have an ArgumentException
for the case the passed string is empty -- that is, I want to catch that generically and not explicitly test for it.)
Except that:
Given roughly the example given, all you care about is that reading the file failed - IFF it failed, you need to communicate that up the call chain.
To repeat: You want to communicate up the call chain that reading the file failed and why is only secondary.
When did reading (processing) the file fail: When any exception is thrown.
So what you really want to do is catch any exception, contextualize it with what you wanted to do (say, add the filename) and then return or rethrow something that indicates what went wrong and why it went wrong ( that would be the actual "inner" exception).
For this, the example is (nearly) spot on:
- "Up the call chain" in this case is the user directly at the console
- It "returns" the error as a string to be read by the "user", which is appropriate for a simple consle program.
- It communicates what went wrong clearly. (It should include the filename passed to
StreamReader
though.)
- It includes why it went wrong, namely the exception message. (It possibly should also include the call stack.)
By example:
Say that this example is slightly more complex and the file name is user provided. The the string being empty is then (a) a normal case and maybe (b) a user error that might not warrant special handling in the code, because the general handling provided -- that is, reporting that reading the file failed -- is totally enough.
By catching only IOException
as recommended above, the user entering an empty filename would either crash the application or require an additional catch block that would essentially do the same thing as the other catch block: Report that reading the file failed and why.
Independent observations: Found this nice piece: http://www.codeproject.com/Articles/7557/Exception-Handling-in-C-with-the-quot-Do-Not-Catch where the author is certainly more constructive than my "utterly useless" statement but essentially has a similar conclusion (with a different, certainly valid, solution): (emph. added)
If we follow Microsoft's guidelines then we have to catch only those
exceptions that could be triggered by the File.Copy
method. If you
look in the .NET Framework's Class Library, you'll see that this is
UnauthorizedAccessException, (...). If you
ask me, catching all these exceptions individually is not doable. All
I wanted to know is whether or not a file copy failed or not. It would
be sufficient to only capture IOException, ArgumentException and
NotSupportedException (because all the other exceptions derive from
these three exceptions) but to know this I have to read the
documentation again. I really don't want to go through that much
trouble to simply copy a file.
The guideline assumes that we know all the exceptions that can be
thrown by the task executed. Copying a file is a very simple operation
that is properly documented by Microsoft. But what if we're using some
third-party tool? The stability of our unattended tool depends on the
quality of the documentation of this tool. If this third-party forgets
to mention one of the exceptions that their tool throws in the
documentation, then our unattended application could stop prematurely.