I\'m refactoring a medium-sized WinForms application written by other developers and almost every method of every class is surrounded by a try-catch
block. 99% of t
"To log exceptions appropriately and prevent them from propagating to the user, have an Application.ThreadException handler"
Would you then be able to tell the user what happened? Would all exceptions end up there?
"For cases where there's a resource that needs cleanup, leave the try-catch block as it is"
You can use try-finally
blocks as well if you wish to let the exception be handled elsewhere. Also consider using the using
keyword on IDisposable
resources.
"In methods that "return-false-on-error", let the exception propagate and catch it in the caller instead"
It depends on the method. Exceptions should occur only in exceptional situations. A FileNotFoundException
is just weird for the FileExists()
method to throw, but perfectly legal to be thrown by OpenFile()
.
You may try to use AOP.
In AOP through PostSharp, for example, you can handle exceptions in one central place (piece of code) as an aspect.
Look at the examples in documentation to have an idea => Docs on Exception Handling with PostSharp.
I think your strategy of removing try/catch block which just appear to do generic thoughtless logging is fine. Obviously leaving the cleanup code is necessary. However, I think more clarification is needed for your third point.
Return false on error methods are usually OK for things where exceptions are unavoidable, like a file operation in your example. Whereas I can see the benefit of removing exception handling code where it's just been put in thoughtlessly, I would consider carefully what benefit you get by pushing responsibility for handling an exception of this kind higher up in the call chain.
If the method is doing something very specific (it's not generic framework code), and you know which callers are using it, then I'd let it swallow the exception, leaving the callers free of exception handling duties. However, if it's something more generic and maybe more of a framework method, where you're not sure what code will be calling the method, I'd maybe let the exception propagate.
The best is as said by others, do exception handling at 1 place. Its bad practice to conceal the raised exception rather than allowing to bubble up.
You should only handle only the exceptions that you are expecting, know how to handle and they are not corrupt the state of your application, otherwise let them throw.
A good approach to follow is to log the exception first, then Restart your application, just like what Microsoft did when office or visual studio crashing. To do so you have to handle the application domain unhanded exception, so:
AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException;
//Add these two lines if you are using winforms
Application.ThreadException += OnApplicationThreadException;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
private void OnCurrentDomainUnhandledException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
//Log error
//RestartTheApplication
}
Here an example on how to restart your application.
For cleanup rather use try-finally
or implement the IDisposable
as suggested by Amittai. For methods that return bool on error rather try and return false if the condition is not met. Example.
bool ReturnFalseExample() {
try {
if (1 == 2) thow new InvalidArgumentException("1");
}catch(Exception e) {
//Log exception
return false;
}
Rather change to this.
bool ReturnFalseExample() {
if (1 == 2) {
//Log 1 != 2
return false;
}
If i'm not mistaken try catches
are an expensive process and when possible you should try determine if condition is not met rather then just catching exceptions.
}