简体   繁体   中英

What is best practice for error handling in C#? [on hold]

So lately, I've been error-proofing a desktop app to get ready for production. AFAIK the only way to test methods for error is using try-catch . The only issue I have with try-catch is that the extra bracketing can make code look confusing. So lately, I've been doing this:

    public DoSomething()
    {
        try 
        {
            DoThing(object a, object b);
        }
        catch (SpecificExceptionA a)
        {
            logger.log($"An error was caused by {a.GetType().Name} because of ...");
        }
        catch (SpecificExceptionB b)
        {
            logger.log($"An error was caused by {b.GetType().Name} because of ... This is really bad.")
            throw b;
        }

        ...

        DoThing(object a, object b) {
        //Things are done here...
        }
    }

Is there a better way of doing this?

This is good. One potential improvement is to rethrow with throw; , not throw ex; .

try 
{
    DoThing(object a, object b);
}
catch (SpecificExceptionA a)
{
    logger.log(...);
}
catch (SpecificExceptionB b)
{
    logger.log(...)
    throw; 
}

throw preserves the original thrower, throw ex; would result in the current method appearing as the source. What is appropriate for each case depends on how the exception is handled upstream.


A minor thing would be to call your variables ex or e to follow the convention.


Here's an example with multiple catches from the official doco: Using Exceptions (C# Programming Guide) .

 try { using (var sw = new StreamWriter(@"C:\test\test.txt")) { sw.WriteLine("Hello"); } } // Put the more specific exceptions first. catch (DirectoryNotFoundException ex) { Console.WriteLine(ex); } catch (FileNotFoundException ex) { Console.WriteLine(ex); } // Put the least specific exception last. catch (IOException ex) { Console.WriteLine(ex); }

There are two articles on Exception that I link often:

You got a number of issues there including:

  • not logging all exception details, particular Exception.ToString()
  • rethrowing on the exception with throw b; rather then throw; (the former clears the very important stacktrace)
  • throwing on after logging, wich tends to flood the logfiles with repetition

You don't really need to wrap every single method call in a try / catch . You only need to put them where you plan to handle the exception. In a desktop application (eg WinForms), this typically means in two places:

  1. Where an exception represents an alternative flow, eg handling the case where a file is not found and the user must be notified. In this case, wrap only the specific methods that access the file.

  2. At the top level (eg in any event handler) to prevent your application from crashing.

Exceptions that you do not plan to handle can/should be allowed to bubble up, since you have no defined behavior to handle them.

If you have a series of objects that need to be processed, and you want some to be able to fail while the others succeed, I would wrap the exception inside the method being called and return a success or failure code.

bool TryDoSomething(MyObject thing)
{
    try
    {
        thing.DoTheWork();
        return true;
    }
    catch(SpecificException exception)
    {
        Log(exception.Message);
        return false;
    }
}

Then in your main code:

int counter = 0;
foreach (var item in list)
{
    counter += TryDoSomething(item) ? 1 : 0;
}
Log("{0} of {1} transactions succeeded.", counter, list.Count);

I may add something else about logging errors, to log an error, the best practice for this not to give special message (just in case of logging) but to log the entire exception(that will lead you to popular Problems With Log Files),and in front of your method log something like "log.Debug("i am doing this thing");", while the logger will take care of the rest:

try
{
   log.Debug("Creating a foo");

   using (var context = new ApplicationDbContext())
   {
      var foo = new Foo();
      foo.RequiredInt = (int) requiredInt;
      foo.FooString = fooString;

      context.Foos.Add(foo);
      context.SaveChanges();

   }
}
catch (Exception ex)
{
   log.Error(ex);
}

there are lots of log viewer to make the log written this way more clean and easy to read... you can read about it in details in https://stackify.com/csharp-logging-best-practices/

Looks ok, I would also add a generic Exception right at the bottom in case in case there is an exception thrown which cannot be handled by these specific exceptions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM