It is discouraged to simply catch System.Exception
. Instead, only the "known" exceptions should be caught.
Now, this sometimes leads to unneccessary repetitive code, for example:
try
{
WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
WebId = Guid.Empty;
}
catch (OverflowException)
{
WebId = Guid.Empty;
}
I wonder: Is there a way to catch both exceptions and only call the WebId = Guid.Empty
call once?
The given example is rather simple, as it's only a GUID
. But imagine code where you modify an object multiple times, and if one of the manipulations fail in an expected way, you want to "reset" the object
. However, if there is an unexpected exception, I still want to throw that higher.
Maybe try to keep your code simple such as putting the common code in a method, as you would do in any other part of the code that is not inside a catch clause?
E.g.:
Just how I would do it, trying to find the simple is beautiful pattern
Note that I did find one way to do it, but this looks more like material for The Daily WTF:
EDIT: I do concur with others who are saying that, as of C# 6.0, exception filters are now a perfectly fine way to go:
catch (Exception ex) when (ex is ... || ex is ... )
Except that I still kind of hate the one-long-line layout and would personally lay the code out like the following. I think this is as functional as it is aesthetic, since I believe it improves comprehension. Some may disagree:
ORIGINAL:
I know I'm a little late to the party here, but holy smoke...
Cutting straight to the chase, this kind of duplicates an earlier answer, but if you really want to perform a common action for several exception types and keep the whole thing neat and tidy within the scope of the one method, why not just use a lambda/closure/inline function to do something like the following? I mean, chances are pretty good that you'll end up realizing that you just want to make that closure a separate method that you can utilize all over the place. But then it will be super easy to do that without actually changing the rest of the code structurally. Right?
I can't help but wonder (warning: a little irony/sarcasm ahead) why on earth go to all this effort to basically just replace the following:
...with some crazy variation of this next code smell, I mean example, only to pretend that you're saving a few keystrokes.
Because it certainly isn't automatically more readable.
Granted, I left the three identical instances of
/* write to a log, whatever... */ return;
out of the first example.But that's sort of my point. Y'all have heard of functions/methods, right? Seriously. Write a common
ErrorHandler
function and, like, call it from each catch block.If you ask me, the second example (with the
if
andis
keywords) is both significantly less readable, and simultaneously significantly more error-prone during the maintenance phase of your project.The maintenance phase, for anyone who might be relatively new to programming, is going to comprise 98.7% or more of the overall lifetime of your project, and the poor schmuck doing the maintenance is almost certainly going to be someone other than you. And there is a very good chance they will spend 50% of their time on the job cursing your name.
And of course FxCop barks at you and so you have to also add an attribute to your code that has precisely zip to do with the running program, and is only there to tell FxCop to ignore an issue that in 99.9% of cases it is totally correct in flagging. And, sorry, I might be mistaken, but doesn't that "ignore" attribute end up actually compiled into your app?
Would putting the entire
if
test on one line make it more readable? I don't think so. I mean, I did have another programmer vehemently argue once long ago that putting more code on one line would make it "run faster." But of course he was stark raving nuts. Trying to explain to him (with a straight face--which was challenging) how the interpreter or compiler would break that long line apart into discrete one-instruction-per-line statements--essentially identical to the result if he had gone ahead and just made the code readable instead of trying to out-clever the compiler--had no effect on him whatsoever. But I digress.How much less readable does this get when you add three more exception types, a month or two from now? (Answer: it gets a lot less readable).
One of the major points, really, is that most of the point of formatting the textual source code that we're all looking at every day is to make it really, really obvious to other human beings what is actually happening when the code runs. Because the compiler turns the source code into something totally different and couldn't care less about your code formatting style. So all-on-one-line totally sucks, too.
Just saying...
Since I felt like these answers just touched the surface, I attempted to dig a bit deeper.
So what we would really want to do is something that doesn't compile, say:
The reason we want this is because we don't want the exception handler to catch things that we need later on in the process. Sure, we can catch an Exception and check with an 'if' what to do, but let's be honest, we don't really want that. (FxCop, debugger issues, uglyness)
So why won't this code compile - and how can we hack it in such a way that it will?
If we look at the code, what we really would like to do is forward the call. However, according to the MS Partition II, IL exception handler blocks won't work like this, which in this case makes sense because that would imply that the 'exception' object can have different types.
Or to write it in code, we ask the compiler to do something like this (well it's not entirely correct, but it's the closest possible thing I guess):
The reason that this won't compile is quite obvious: what type and value would the '$exception' object have (which are here stored in the variables 'e')? The way we want the compiler to handle this is to note that the common base type of both exceptions is 'Exception', use that for a variable to contain both exceptions, and then handle only the two exceptions that are caught. The way this is implemented in IL is as 'filter', which is available in VB.Net.
To make it work in C#, we need a temporary variable with the correct 'Exception' base type. To control the flow of the code, we can add some branches. Here goes:
The obvious disadvantages for this are that we cannot re-throw properly, and -well let's be honest- that it's quite the ugly solution. The uglyness can be fixed a bit by performing branch elimination, which makes the solution slightly better:
That leaves just the 're-throw'. For this to work, we need to be able to perform the handling inside the 'catch' block - and the only way to make this work is by an catching 'Exception' object.
At this point, we can add a separate function that handles the different types of Exceptions using overload resolution, or to handle the Exception. Both have disadvantages. To start, here's the way to do it with a helper function:
And the other solution is to catch the Exception object and handle it accordingly. The most literal translation for this, based on the context above is this:
So to conclude:
It is worth mentioning here. You can respond to the multiple combinations (Exception error and exception.message).
I ran into a use case scenario when trying to cast control object in a datagrid, with either content as TextBox, TextBlock or CheckBox. In this case the returned Exception was the same, but the message varied.
This is a classic problem every C# developer faces eventually.
Let me break your question into 2 questions. The first,
Can I catch multiple exceptions at once?
In short, no.
Which leads to the next question,
How do I avoid writing duplicate code given that I can't catch multiple exception types in the same catch() block?
Given your specific sample, where the fall-back value is cheap to construct, I like to follow these steps:
So the code looks like:
If any exception is thrown, then WebId is never set to the half-constructed value, and remains Guid.Empty.
If constructing the fall-back value is expensive, and resetting a value is much cheaper, then I would move the reset code into its own function: