Catch multiple exceptions at once?

前端 未结 27 1838
夕颜
夕颜 2020-11-22 11:31

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

Now, this sometimes leads to unnecce

相关标签:
27条回答
  • 2020-11-22 12:17

    Wanted to added my short answer to this already long thread. Something that hasn't been mentioned is the order of precedence of the catch statements, more specifically you need to be aware of the scope of each type of exception you are trying to catch.

    For example if you use a "catch-all" exception as Exception it will preceed all other catch statements and you will obviously get compiler errors however if you reverse the order you can chain up your catch statements (bit of an anti-pattern I think) you can put the catch-all Exception type at the bottom and this will be capture any exceptions that didn't cater for higher up in your try..catch block:

                try
                {
                    // do some work here
                }
                catch (WebException ex)
                {
                    // catch a web excpetion
                }
                catch (ArgumentException ex)
                {
                    // do some stuff
                }
                catch (Exception ex)
                {
                    // you should really surface your errors but this is for example only
                    throw new Exception("An error occurred: " + ex.Message);
                }
    

    I highly recommend folks review this MSDN document:

    Exception Hierarchy

    0 讨论(0)
  • 2020-11-22 12:18

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

    0 讨论(0)
  • 2020-11-22 12:20

    Cautioned and Warned: Yet another kind, functional style.

    What is in the link doesn't answer your question directly, but it's trivial to extend it to look like:

    static void Main() 
    { 
        Action body = () => { ...your code... };
    
        body.Catch<InvalidOperationException>() 
            .Catch<BadCodeException>() 
            .Catch<AnotherException>(ex => { ...handler... })(); 
    }
    

    (Basically provide another empty Catch overload which returns itself)

    The bigger question to this is why. I do not think the cost outweighs the gain here :)

    0 讨论(0)
  • 2020-11-22 12:22

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

    try
    {
        // ...
    }
    catch (FormatException)
    {
        DoSomething();
    }
    catch (OverflowException)
    {
        DoSomething();
    }
    
    // ...
    
    private void DoSomething()
    {
        // ...
    }
    

    Just how I would do it, trying to find the simple is beautiful pattern

    0 讨论(0)
  • 2020-11-22 12:25

    So you´re repeating lots of code within every exception-switch? Sounds like extracting a method would be god idea, doesn´t it?

    So your code comes down to this:

    MyClass instance;
    try { instance = ... }
    catch(Exception1 e) { Reset(instance); }
    catch(Exception2 e) { Reset(instance); }
    catch(Exception) { throw; }
    
    void Reset(MyClass instance) { /* reset the state of the instance */ }
    

    I wonder why no-one noticed that code-duplication.

    From C#6 you furthermore have the exception-filters as already mentioned by others. So you can modify the code above to this:

    try { ... }
    catch(Exception e) when(e is Exception1 || e is Exception2)
    { 
        Reset(instance); 
    }
    
    0 讨论(0)
  • 2020-11-22 12:26

    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:

    catch (Exception ex) when (
        ex is ...
        || ex is ...
        || ex is ...
    )
    

    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?

    private void TestMethod ()
    {
        Action<Exception> errorHandler = ( ex ) => {
            // write to a log, whatever...
        };
    
        try
        {
            // try some stuff
        }
        catch ( FormatException  ex ) { errorHandler ( ex ); }
        catch ( OverflowException ex ) { errorHandler ( ex ); }
        catch ( ArgumentNullException ex ) { errorHandler ( ex ); }
    }
    

    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:

    try
    {
        // try some stuff
    }
    catch( FormatException ex ){}
    catch( OverflowException ex ){}
    catch( ArgumentNullException ex ){}
    

    ...with some crazy variation of this next code smell, I mean example, only to pretend that you're saving a few keystrokes.

    // sorta sucks, let's be honest...
    try
    {
        // try some stuff
    }
    catch( Exception ex )
    {
        if (ex is FormatException ||
            ex is OverflowException ||
            ex is ArgumentNullException)
        {
            // write to a log, whatever...
            return;
        }
        throw;
    }
    

    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 and is 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...

    // super sucks...
    catch( Exception ex )
    {
        if ( ex is FormatException || ex is OverflowException || ex is ArgumentNullException )
        {
            // write to a log, whatever...
            return;
        }
        throw;
    }
    
    0 讨论(0)
提交回复
热议问题