9

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 the time these catch blocks only log exceptions or cleanup resources and return error status.

I think it is obvious that this application lacks proper exception-handling mechanism and I'm planning to remove most try-catch blocks.

Is there any downside of doing so? How would you do this? I'm planning to:

  • To log exceptions appropriately and prevent them from propagating to the user, have an Application.ThreadException handler

  • For cases where there's a resource that needs cleanup, leave the try-catch block as it is

Update: Using using or try-finally blocks is a better way. Thanks for the responses.

  • In methods that "return-false-on-error", let the exception propagate and catch it in the caller instead

Any corrections/suggestions are welcome.

Edit: In the 3rd item, with "return-false-on-error" I meant methods like this:

bool MethodThatDoesSomething() {
    try {
       DoSomething(); // might throw IOException
    } catch(Exception e) {
       return false;
    }
}

I'd like to rewrite this as:

void MethodThatDoesSomething() {
   DoSomething(); // might throw IOException
}

// try-catch in the caller instead of checking MethodThatDoesSomething's return value
try {
   MethodThatDoesSomething()
} catch(IOException e) {
   HandleException(e);
}
henginy
  • 2,041
  • 1
  • 16
  • 27
  • 8
    For cleanup you may want to implement IDisposable and have some "using" blocks – Amittai Shapira Aug 10 '11 at 08:09
  • 5
    In those methods where you still need to catch exceptions, don't do a general `catch(Exception)` but rather find out exactly which exceptions can be thrown and handle these. Other/unexpected exceptions should probably be propagated to the user or logged as exceptional cases. – Andreas Ågren Aug 10 '11 at 08:13
  • Thanks, I've updated my question to include these points. – henginy Aug 10 '11 at 08:58

8 Answers8

2

"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().

C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72
  • 1) Yeah all exceptions end there and you should use that for stuff you cant handle in the normal program flow and you should only use try and catch when you can handle the error not to ignore the error. – Skomski Aug 10 '11 at 08:22
  • I misinterpreted the qeustion #1 in that case. I agree it's nice to handle unhandleable ones that way. – C.Evenhuis Aug 10 '11 at 08:28
  • Thanks for the comments. For the 1st case, yes it will handle all unhandled exceptions there as Skomski said. For the 3rd case, please see my edit. – henginy Aug 10 '11 at 08:31
2

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

Jethro
  • 5,896
  • 3
  • 23
  • 24
1

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.

Andrea Colleoni
  • 5,919
  • 3
  • 30
  • 49
  • 1
    I like the idea of AOP but my impression so far is that AOP frameworks are not mature enough for production use. I'd like to be proved wrong, though, it is a great concept. – henginy Aug 10 '11 at 08:54
1

As an option for "return-false-on-error" you can clean up the code this way:

    static class ErrorsHelper {
        public static bool ErrorToBool(Action action) {
            try {
                action();
                return true;
            } catch (Exception ex) {
                LogException(ex);

                return false;
            }
        }

        private static void LogException(Exception ex) {
            throw new NotImplementedException();
        }
    }

and usage example:

    static void Main(string[] args) {
        if (!ErrorToBool(Method)) {
            Console.WriteLine("failed");
        } else if (!ErrorToBool(() => Method2(2))) {
            Console.WriteLine("failed");
        }
    }

    static void Method() {}

    static void Method2(int agr) {}
  • Thank you, however the code I gave as example stems from procedural thinking imo. I'd like to get rid of that. Your solution is nice syntactic sugar covering it. – henginy Aug 10 '11 at 12:05
1

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.

Zenwalker
  • 1,883
  • 1
  • 14
  • 27
1

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.

Community
  • 1
  • 1
Jalal Said
  • 15,906
  • 7
  • 45
  • 68
  • I knew about Application.ThreadException, but thanks for AppDomain.CurrentDomain.UnhandledException. I'm not sure if restarting the application is a good idea for my case since it takes some time. – henginy Aug 10 '11 at 12:56
  • If you don't know how to **fix** the error or if it corrupt the state of your application, then you have no choice but to either blow up the application or just do restart "maybe after dialog show to user or report the error to your email", that what all big projects and applications do. – Jalal Said Aug 10 '11 at 17:05
1

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.

Alex Humphrey
  • 6,099
  • 4
  • 26
  • 41
  • Thanks, you got my point. I agree that it makes sense to swallow an exception if letting it propagate will not yield much benefit, compared to leaving the callers free of handling it. I guess I don't appreciate code like: "if(!customerDb.InsertCustomer(params)) { ... }". Isn't it procedural-like and ugly for you too? Or am I getting too caught up in the aesthetics? :) (I think it's more than that though) – henginy Aug 10 '11 at 12:40
  • @henginy - I personally don't find it ugly or very procedural compared to a try/catch, although it does start to feel a little C-like. Just be careful of falling into the trap of using exceptions for control flow. – Alex Humphrey Aug 10 '11 at 13:01
0

we can remove try and catch by adding condition Like

 string emailAddresses = @"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$";
        if (!Regex.IsMatch(Email, emailAddresses))
        {
            throw new UserFriendlyException($"E-mail Address Is not Valid");
        }**strong text**