Tech Off Thread

24 posts

Doing the same thing for multiple exception types

Back to Forum: Tech Off
  • User profile image
    Sven Groot

    Quite often I find I have to do the same thing for multiple exception types that have no common base except Exception. A very common example of this is with file IO where I want to handle both IOException and UnauthorizedAccessException:

    try
    {
       // some file IO stuff
    }
    catch( IOException ex )
    {
       ShowErrorMessage(ex);
    }
    catch( UnauthorizedAccessException ex )
    {
       ShowErrorMessage(ex);
    }


    Writing all these exception handlers that do the same is rather cumbersome. An alternative would be this

    try
    {
       // some file IO stuff
    }
    catch( Exception ex )
    {
       if( ex is IOException || ex is UnauthorizedAccessException )
          ShowErrorMessage(ex);
       else
          throw;
    }


    With VB you can use filtered exceptions:

    Try
       ' Some file IO stuff
    Catch ex As Exception When TypeOf ex Is IOException OrElse TypeOf ex Is UnauthorizedAccessException
       ShowErrorMessage(ex)
    End Try


    However none of these feels "right" to me somehow.

    What does everyone prefer to do in such a situation?

  • User profile image
    Minh

    I prefer the following 'cuz it's more readable...

    catch( IOException ex )
    {
       ShowErrorMessage(ex);
    }
    catch( UnauthorizedAccessException ex )
    {
       ShowErrorMessage(ex);
    }

    ...and that absolute minimizing of keystrokes isn't that good a goal for a language.

  • User profile image
    DinoViehland

    The first and last forms are the best.  The middle one is actually different from the VB one. 

    The key here is the the difference between catches, finally's, and filters and when they run.  There are two passes to exception handling (http://blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx).  The catch runs on the 2nd pass, but the filter (the when clause in VB) runs on the 1st pass - that's also where finally's run.  Catching an exception (interrupting the 1st pass) and rethrowing is generally considered bad.  For example you interrupt the debugging experience and you raise a 2nd exception (and exceptions aren't cheap).  There's probably other reasons out there as well.

    So 1 or 3, never 2.

  • User profile image
    Sven Groot

    I just realized I didn't specificy my own preference. In C# I always use the first form. In VB I will use the first form or occasionally the third if I remember it. I have never used the second form for the reasons Dino gives, but I thought I'd list it because in C# it's the only alternative.

    On a related topic, I find it peculiar that VB is the only CLR language that supports filtered exceptions.

  • User profile image
    Yggdrasil

    Sven Groot wrote:
     if( ex.GetType() == typeof(IOException) || ex.GetType() == typeof(UnauthorizedAccessException) )


    A bit of a tangent, but why not use the slightly less verbose
    if (ex is IOException || ex is UnauthorizedAccessException)?

    The results are a bit different than your code (it will catch derived exceptions as well), but it's the same behavior as your first example with catch (IOException ex).

  • User profile image
    Nikster

    If you're catching all the other exceptions that can be thrown can't you just have a

    catch( Exception ex )
    {
       ShowErrorMessage(ex);
    }

    at the end ?

  • User profile image
    Sven Groot

    Yggdrasil wrote:
    
    Sven Groot wrote:
     if( ex.GetType() == typeof(IOException) || ex.GetType() == typeof(UnauthorizedAccessException) )


    A bit of a tangent, but why not use the slightly less verbose
    if (ex is IOException || ex is UnauthorizedAccessException)?

    The results are a bit different than your code (it will catch derived exceptions as well), but it's the same behavior as your first example with catch (IOException ex).

    Because I made that post early in the morning and didn't remember that syntax. Embarassed

    Nikster: I'm not trying to catch all exceptions, and generally that's a very bad thing to do.

  • User profile image
    Nikster

    Catching all exceptions is a bad thing to do ? if you don't handle them won't your application eventually crash if an exception is not caught ? well not crash, but cause an exception at app/OS level.

    Unless of course you're meaning you want to do multiple groups and the display message was just an example rather than a real case.

    so you could still do a catch( Exception ex) and within do something like if( ex is IOException .... etc, unless I'm totally missing what you're saying Wink



  • User profile image
    blowdart

    Nikster wrote:
    Catching all exceptions is a bad thing to do



    Yes. You should only catch exceptions you can handle. Other exceptions should contain upwards.

    At your top level error handler then yes, catch Exception (or rather ApplicationException) and log it, but do not catch Exception at a lower level unless you're determined to just swallow all errors.

  • User profile image
    Sven Groot

    Catching Exception is bad. Their are runtime errors than can happen in the framework that you can't possibly recover from (e.g. OutOfMemoryException). catch( Exception ) will catch (most of) these as well. At which point the app may be in such a bad state that your attempt to show an error message will also fail, thus causing a new exception and the app crashes anyway. Except now, the root cause is much harder to find because you swallowed the original exception.

    On some exceptions the only reasonable thing you can do is crash. That's why you always want to catch specific exceptions, never Exception itself. Catching Exception is only acceptable if you rethrow afterwards, as in my second example, but even then I wouldn't recommend it.

  • User profile image
    JChung2006

    Sven Groot wrote:
    On a related topic, I find it peculiar that VB is the only CLR language that supports filtered exceptions.

    F# could support filtered exceptions via pattern matching.

    Try-catch expressions. try e1 with rules is a try-catch expression. The expression e1 is evaluated and if an exception occurs then the pattern rules are executed against the resulting exception value. If no rule matches the exception is rethrown. The type ty of the overall expression is the same as the type of e1, and each rule of a try/with expression must match values of type exn (equivalent to System.Exception) and return values of type ty.

    IronPython could support filtered exceptions.  Python has concise syntax to handle that.  However, I haven't worked with IronPython enough to know how well CLR exceptions map to Python exceptions.

    ... try:
    ... except (RuntimeError, TypeError, NameError):
    ...     pass

    I wonder if IronRuby could support it or not. Ruby supports try...catch...finally semantics. It doesn't require "try," and its version of catch is "rescue" and finally is "ensure."

    JavaScript 1.5 could support filtered exceptions, but ECMAScript couldn't.  Microsoft's JScript implementations to date are ECMAScript-compliant only.

    // JavaScript 1.5+
    try
    {

    }
    catch (e if typeof e == System.IO.IOException || typeof e == System.UnauthorizedAccessException)
    {
        showErrorMessage(e)
    }

  • User profile image
    littleguru

    I'm always using 1 although I know that VB.NET is using exception filters that are already implemented at the CLR level...

    I find that 1 is the most readable version.

  • User profile image
    Richard.Hein

    You could make ShowErrorMessage() overloaded, accepting the types of exceptions you want.

  • User profile image
    ScanIAm

    Sven Groot wrote:
    

    Catching Exception is bad. Their are runtime errors than can happen in the framework that you can't possibly recover from (e.g. OutOfMemoryException). catch( Exception ) will catch (most of) these as well. At which point the app may be in such a bad state that your attempt to show an error message will also fail, thus causing a new exception and the app crashes anyway. Except now, the root cause is much harder to find because you swallowed the original exception.

    On some exceptions the only reasonable thing you can do is crash. That's why you always want to catch specific exceptions, never Exception itself. Catching Exception is only acceptable if you rethrow afterwards, as in my second example, but even then I wouldn't recommend it.



    I'm not sure I buy that.  In some cases, you don't know what exception will be thrown, and in others, you are trying to figure out what exception happened.

    I'm all for re-throwing an exception if it isn't for you, but I like to be able to trace what has happened.  I'll agree that in a low resources condition, you may never see the issue, but in all other cases, it would be nice to be able to catch errors on a boundary.  (for example, between the data-layer and the business layer).

  • User profile image
    ScanIAm

    Here's an example I've had to use due to having to use some flaky software and even flakier mainframe:

    for (int iTries = 0; ; iTries++)
    {
      try
      {
        Result = DoSomething();
      }
      catch(Exception ex)
      {
        if(!Retryable(ex.Message, iTries))
          throw ex;
      }
    }


    The server side will sometimes time out, or not respond, or produce some other unexpected action when DoSomething() is called. 

    In most cases, just trying this again will solve the problem, but in others, the exception is truly a problem.

  • User profile image
    stevo_

    There are many things wrong with that code, even if we are to accept the reason for why you would do such a thing..

  • User profile image
    JChung2006

    ScanIAm wrote:
    for (int iTries = 0; ; iTries++)
    {
      try
      {
        Result = DoSomething();
      }
      catch(Exception ex)
      {
        if(!Retryable(ex.Message, iTries))
          throw ex;
      }
    }

    Your code will only exit the for loop if an exception is thrown.  WTF?

  • User profile image
    ScanIAm

    JChung2006 wrote:
    
    ScanIAm wrote:
    for (int iTries = 0; ; iTries++)
    {
      try
      {
        Result = DoSomething();
      }
      catch(Exception ex)
      {
        if(!Retryable(ex.Message, iTries))
          throw ex;
      }
    }

    Your code will only exit the for loop if an exception is thrown.  WTF?


    It is a pared down version of the code and I forgot the 'break;' after the call to DoSomething();

    for (int iTries = 0; ; iTries++)
    {
      try
      {
        Result = DoSomething();
        break;
      }
      catch(Exception ex)
      {
        if(!Retryable(ex.Message, iTries))
          throw ex;
      }
    }


    Retryable() takes the exception and the current tries and decides if we've tried this thing too many times.  If so, then we throw it up the chain.

    That way, I can retry some exceptions 10 times and other exceptions 2 times and simply return false if we exceed this count or if we receive an exception that we can't retry.

    I agree it's ugly, but you don't get to choose the software you interface with in all cases. 

    In this case, the call to DoSomething() will only return a value if it is completely successful.  It makes a webservice call to another server that will communicate with a mainframe.  The software that does this communication with the mainframe can only handle things in a linear fashion and as such, will throw an execption for any minor deviation.

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.