Sunday, May 27, 2012

Catch multiple Exceptions at once?


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/


Source: Tips4all

9 comments:

  1. Catch System.Exception and switch on the types

    catch (Exception ex)
    {
    if (ex is FormatException ||
    ex is OverflowException)
    {
    WebId = Guid.Empty;
    return;
    }
    else
    {
    throw;
    }
    }

    ReplyDelete
  2. 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();
    }

    ReplyDelete
  3. @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.

    ReplyDelete
  4. 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
    }

    ReplyDelete
  5. catch (Exception ex)
    {
    if (ex is FormatException ||
    ex is OverflowException)
    {} else throw;

    WebId = Guid.Empty;
    }

    ReplyDelete
  6. catch (Exception ex)
    {
    if (!(
    ex is FormatException ||
    ex is OverflowException))
    {
    throw;
    }

    Console.WriteLine("Hello");
    }

    ReplyDelete
  7. 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;
    }
    }

    ReplyDelete
  8. How about
    try

    {
    WebId = Guid.Empty;
    WebId = new Guid(queryString["web"]);
    }
    catch (FormatException)
    {
    }
    catch (OverflowException)
    {
    }

    ReplyDelete
  9. Design an exception inheritance hierarchy for your application.

    ReplyDelete