tags:

views:

9664

answers:

10

It is discouraged to simply catch System.Exception, instead only the "known" Exceptions should be caught.

Now, this sometimes leads to unneccessary repetetive 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?

Edit: 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.

About the Answer: Thanks everyone! For some reason, I had my mind set on a switch-case statement which does not support switching on GetType(). Now, there were two answers, one using "typeof" and one using "is". I first thought "typeof()" would be my Function because I thought "Hey, I only want to catch FormatException because that's the only thing I expect". But that's not how catch() works: catch also catches all derived exceptions. After thinking about it, this is really obvious: Otherwise, catch(Exception ex) would not work! So the correct answer is "is". Yay, learned two things with only one question \o/

+1  A: 

Note that I did find one way to do it, but this looks more like Material for TheDailyWTF:

            catch (Exception ex)
            {

                switch (ex.GetType().Name)
                {
                    case "System.FormatException":
                    case "System.OverflowException":
                        WebId = Guid.Empty;
                        break;
                    default:
                        throw;                           
                }
            }
Michael Stum
-1 vote, +5 WTF :-) This should not have been marked as an answer, but it is he-larious.
Aaron
it's not marked as answer, it's in that fuzzy blue color because i'm the one who asked the question :) the Answer is green.
Michael Stum
good grief.....
AdamRalph
+1  A: 

How about try

        {
            WebId = Guid.Empty;
            WebId = new Guid(queryString["web"]);
        }
        catch (FormatException)
        {
        }
        catch (OverflowException)
        {
        }
Maurice
That works only if the Catch-Code can be fully moved into the Try-Block. But imaging code where you make multiple manipulations to an object, and one in the middle fails, and you want to "reset" the object.
Michael Stum
In that case I would add a reset function and call that from multiple catch blocks.
Maurice
+60  A: 

Catch System.Exception and switch on the types

       catch (Exception ex)            
       {                
           if (ex is FormatException ||
               ex is OverflowException)
           {
               WebId = Guid.Empty;
               return;
           }
           else
           {
               throw;
           }
       }
Joseph Daigle
shouldn't it be: else { throw ex; } ?
Alex Baranosky
You don't have to put the "ex" in there. The throw; is sufficient.
mkelley33
throw ex is one if those really common mistakes. As a rule of thumb: You NEVER want to throw ex, since that generates a new exception, with an empty call stack. throw simply throws the existing exception higher.
Michael Stum
Unfortunately, FxCop (ie - Visual Studio Code Analysis) doesn't like it when you catch Exception.
Andrew Garrison
@Andrew... yeah, well, FxCop treats objects like women, man.
Anthony Pegram
+4  A: 

@Micheal

Slightly revised version of your code:

catch (Exception ex)
{
   Type exType = ex.GetType();
   if (exType == typeof(System.FormatException) || 
       exType == typeof(System.OverflowException)
   {
       WebId = Guid.Empty;
   } else {
      throw;
   }
}

String comparisons are ugly and slow.

FlySwat
Why not just use the "is" keyword?
Chris Pietschmann
If I remember right, "is" is a runtime cast, while typeof is a compile type comparison.But I may be wrong.
FlySwat
After having a look at the C# Specification (7.5.11 typeof and 7.9.10 is), i'm accepting this answer as typeof is unambigous. For some reason, I was also too focused on switch..case, which does not work with GetType(), but an if-statement will work as well.
Michael Stum
um...you do realize that this code will silently swallow all other exceptions?
Steven A. Lowe
The two checks have different semantics. The '==' check is an exact type check, whereas the 'is' check is an assignability check. I would think that the latter is more appropriate in this type of scenario.
Greg Beech
One addition though: "Type exType = ex.GetType(); if(exType = .... || exType = ....)" will result in only 1 call to GetType().
Michael Stum
@Greg: I think "is" is not good here: I want to catch exactly System.FormatException. Not sure under what circumstances other types could result in "is System.FormatException" being true, but typeof() seems to be the strictest comparison, as only System.FormatException will be true.
Michael Stum
add an else { throw; } and its good
Steven A. Lowe
@Steven: I've taken the liberty to edit it, you're absolutely right. As said, the reason why i am accepting this answer instead of the others is because I believe after reading about is and typeof, that typeof is the most appropriate here. +1 to all the other answers though.
Michael Stum
@Michael - If Microsoft introduced, say, StringTooLongException derived from FormatException then it is still a format exception, just a specific one. It depends whether you want the semantics of 'catch this exact exception type' or 'catch exceptions that mean the format of the string was wrong'.
Greg Beech
@Michael - Also, note that "catch (FormatException ex) has the latter semantics, it will catch anything derived from FormatException.
Greg Beech
Indeed, you're right, otherwise "Exception ex" would not catch all exceptions. Interesting. Sorry Jonathan, "is" is indeed more appropriate in that case, accepting another answer therefore.
Michael Stum
Shouldn't it be: else { throw ex; } ?
Alex Baranosky
@Alex No. "throw" without "ex" carries the original exception, including original stack trace, up. Adding "ex" makes the stack trace reset, so you really get a different exception than the original. I'm sure someone else can explain it better than me. :)
Stuart Branham
+1  A: 

Here's a method that doesn't convert the Type Name to a string, but instead compares Types directly:

try
{
    WebId = new Guid(queryString["web"]);
}
catch (Exception ex)
{
    if (ex is FormatException || ex is OverflowException)
    {
        WebId = Guid.Empty;
    }
}
Chris Pietschmann
NOTE: this example is broken, missing the else clause to 'throw;'
Aaron
+20  A: 

Not in C# unfortunately, as you'd need an exception filter to do it and C# doesn't expose that feature of MSIL. VB.NET does have this capability though, e.g.

Catch ex As Exception When TypeOf ex Is FormatException OrElse TypeOf ex Is OverflowException

What you could do is use an anonymous function to encapsulate your on-error code, and then call it in those specific catch blocks:

Action onError = () => WebId = Guid.Empty;
try
{
    // something
}
catch (FormatException)
{
    onError();
}
catch (OverflowException)
{
    onError();
}
Greg Beech
Interesting idea and another example that VB.net has some interesting advantages over C# sometimes
Michael Stum
hmmm.... makes me think of using IL rewriting ;)
James Deville
+3  A: 
   catch (Exception ex)            
   {                
       if (ex is FormatException ||
           ex is OverflowException) 
       {} else throw;

       WebId = Guid.Empty;
   }
Konstantin Spirin
+1  A: 
        catch (Exception ex)
        {
            if (!(
                ex is FormatException ||
                ex is OverflowException))
            {
                throw;
            }

            Console.WriteLine("Hello");
        }
Konstantin Spirin
+2  A: 

The accepted answer seems acceptable, except that CodeAnalysis/FxCop will complain about the fact that it's catching a general exception type.

Also, it seems the "is" operator might degrade performance slightly. http://msdn.microsoft.com/en-us/library/ms182271.aspx says to "consider testing the result of the 'as' operator instead", but if you do that, you'll be writing more code than if you catch each exception separately.

Anyhow, here's what I would do:

bool exThrown = false;

try
{
    // something
}
catch( FormatException ){ exThrown = true; }
catch( OverflowException ){ exThrown = true; }

if( exThrown )
{
    // something else
}
Matt
A: 

@Joseph

I like your solution, but it seems to me like it would be better to catch the closest ancestor exception class instead of catching the general Exception class. In this case, it would be SystemException. So I would use the exact same code as you, but with SystemException instead of Exception inside the catch statement.

It is easy to find the closest ancestor class simply by looking up the two different exception classes on MSDN, which gives their full inheritance hierarchies all the way back to the Object class.

@Andrew

Perhaps this would also alleviate FxCop's complaints about catching general exceptions, which you previously commented on in Joseph's solution.

Brandon
John Saunders
@John: I agree that my "answer" is more of a comment than an answer. I wanted to put it in as a comment, but couldn't since you are required to have 50 reputation to comment and I only have 13. So, me being new is exactly why this was the only way I could post my comment. I apologize if putting it in the way I did is inappropriate, and will happily delete it if people do not think it should be here.
Brandon
@Brandon: i said what I meant - it's ok - barely.
John Saunders
I don't believe you can rely on exceptions being derived from System.SystemException. User-defined exceptions are supposed to derive from System.Exception or another common base exception. In any case, Framework Design Guidelines also recommends against catching System.SystemException in most cases.
TrueWill