Exception Handling in C#: Multple Try/Catches vs.

2020-06-23 06:44发布

问题:

Is it good practice to have more than one try{} catch{} statement per method?

回答1:

In my point of view it is good practice to have each method handle only a single task. As such you'll rarely need to have multiple try/catch blocks within a single method. However, I don't see any problems with it.

As Lisa pointed out you should catch specific exceptions and only catch the exceptions the method can actually handle.



回答2:

It's better to have one try/catch with multiple catches to handle each type of Exception differently.



回答3:

If you know the type of Exceptions that could occur beforehand, you can have a single try and catch each of those exceptions, should you want to handle them differently. For example:

try
{
    // a bunch of risky code
}
catch (SpecificException1 ex1)
{
     // handle Specific Exception 1
}
catch (SpecificException2 ex2)
{
     // handle Specific Exception 2
}
catch (SpecificException3 ex3)
{
     // handle Specific Exception 3
}
catch (Exception ex)
{
     // handle an exception that isn't specific
}


回答4:

IMO if you know the exception that might happen before hand you shouldn't use try...catch to get the error.

don't program with exceptions.... so I don't think multiples is a good idea.



回答5:

Generally, I tend to have a lot more finally than catch. Usually, there isn't much specific you can do with an exception, so let it bubble. But the finally ensures you can close things down cleanly etc.



回答6:

For complex production-grade scenarios, it is a horrible practice to have multiple try-catch statements and it is highly inflexible practice to have these statements within the business logic at all.

Windows cloud computing team (their code has to be efficient and reliable) seems to stick with the Exception Handling Action Policies instead.

This code is a better replacement:

// perform action within the policy
policy.Do(() => repository.AddMessages(someMessages));

While the older code blocks look like:

try
{
  repository.AddMessages(someMessages);
}
catch (Exception1 ex)
{
  // dosomething...
}
catch (Exception2 ex)
{
  // second handler
}
catch (Exception3 ex)
{
  // third handler
}

or (that's the Microsoft Enterprise Library way of providing configurable exception handler within hard-coded action policy):

try
{
  repository.AddMessages(someMessages);
}
catch (Exception ex)
{
  bool rethrow = ExceptionPolicy
    .HandleException(ex, "Global Policy");
  if (rethrow)
  {
    throw;
  }
}

Plus, if you have action policy, you can tell it (configure) to log, sleep, retry on certain types of exceptions, instead of simply failing or doing some other hard-coded action.



回答7:

As a rule of thumb, each method should process a single task - this best practice is derived from a test driven environment which makes it far easier to generate tests. It's inherently more difficult to write a test plan for "god" procedures.

It is also therefore a best practice to only use try{} catch{} around items that could fail and only where you would normally catch the exception for useful processing.

Don't use a single try{} catch{} to wrap the entire content of your method thus removing responsibility for decent coding practices.

It is an expensive operation to process exceptions - catch them where necessary and write code that would prevent exceptions occurring elsewhere. There are occasions where it's not inherently simple to prevent an exception, but it can be caught and used productively using a try/catch - for instance checking for exclusivity on file operations.

Make a conscious decision when you use the try/catch, don't just throw it in because you can, that's lazy. Ask yourself "do I need it here?", or "can I do this using a less expensive and/or a more structured approach?".



回答8:

I would say that depends. To me, it looks a little sloppy having all these try-catches everywhere. I try to consolidate to a try block with many catches. Sometimes this doesn't work, you may need to have them separate, but to keep things readable, that's how I prefer it at least.

Also if your method is too long of course, you can extract methods to distribute your try catching.



回答9:

It depends. The purpose of exception handling is just that, handling run time exceptions when they occur.

I typically have one catch all try/catch and then I place try catch blocks around areas of code I know have the potential to throw exceptions (type conversions, etc).



回答10:

The merit of using multiple try/catch blocks is that it clearly pairs the operation you're attempting with the expected exception. Generally speaking, you're not going to catch an exception if the condition that threw it is unrecoverable (unless you're doing something like logging specific exceptions for diagnostics). Code like this:

try
{
   Operation1();
}
catch (MySpecificException1)
{
   RecoverFromExpectedException1();
}
try
{
  Operation2();
}
catch (MySpecificException2)
{
   RecoverFromExpectedException2();
}

may be a little verbose, but that's a consequence of using exceptions for flow control. The important thing is you can tell by looking at this code that the first operation may throw an specific exception, and that your code knows how to recover from this exception and move on to the second operation. And the try/catch blocks aren't doing anything else but that.



回答11:

It is bad practice to even have 1 try/catch per method.

Exceptions were entirely invented so that we can write less error handling code, not more as some other answers suggest.

Before exceptions, you had to check the success of each line of code by testing the return value, and if something was wrong, this had to be passed back up the call stack with a return. This meant every method had to test and return. Exceptions were invented so that methods don't have to require these checks all over the place, and you could have a straight series of code lines that were readable because they weren't obscured by error handling.

So... the advice is, you should have the least amount of try/catches you can have and this should mean most methods won't need any.

But, here's some places where they should be used:

  • When an operation fails (to write to a log file or to display the user a error message), Only do this if you know the program can continue and isn't now in a corrupt state because that one operation failed. Operations have to be isolatable from each other.
  • In your Main method to log any exception that wasn't handled elsewhere before your program terminates because of it.
  • In places where you can take action, such as retry an operation or fallback to a lower mode of operation.
  • Where there's a poor API that won't let you test for a condition you need to handle. For example, if you want to open a file, and the API didn't provide a DoesFileExist() you can call first.

I can't think just now of anywhere else... that's because try/catches should be few and far between!

I always have my debugger set to break when any exception is thrown. It rarely breaks, because exceptions are exceptional.



回答12:

I find consolidating many lines of code that each can throw their own exception into one try block with many catches makes the code hard to read. It's not apparent from just looking at the code what line of code throws what exception. In my opinion, try catches should contain as little code as possible; only the code that can throw the given exception. If the method you are writing contains more than a few try catches, they should each be extracted into their own methods.

This becomes more important if you have more than one method call in your method that throws the same exception. Then they really should be in separate try catches, because when you catch the exception, you generally want to wrap it in a new exception appropriate for the current abstraction with a relevant error message. If you have both statements in the same try catch, you lose the opportunity to give different error messages for the different errors.

Object operationResult;
try {
  operationResult = remoteService.performRemoteOperation();
} catch (RemoteException ex) {
  throw new BusinessException("An error occured when getting ...", ex);
}

// use operation result


标签: c# exception