简体   繁体   中英

What is the best way to re-use exception handling logic in C#?

I have two functions that have different enough logic but pretty much the same exception handling:

public void DoIt1  // DoIt2 has different logic but same exception handling
{
    try
       ... DoIt1 logic
    catch (MySpecialException myEx)
    {
       Debug.WriteLine(myEx.MyErrorString);
       throw;
    }
    catch (Exception e)
    {
       Debug.WriteLine(e.ToString());
       throw;
    }
}

It is not possible to use a single entry point for DoIt1 and DoIt2, because they are called in from outside. Is Copy/Pase (for the exception block) the best approach?

It depends... if there is that much commonality, you could pass in the thing to do as a parameter - either as an interface or a delegate:

void Foo(Action thingToDo) {
    if(thingToDo == null) throw new ArgumentNullException("thingToDo");
    try {
        thingToDo();
    } catch {...} // lots of
}

And call as:

Foo(delegate { /* logic A */ });

Foo(delegate { /* logic B */ });

Try:

public static class Catching<TException> where TException : Exception
{
    public static bool Try<T>(Func<T> func, out T result)
    {
        try
        {
            result = func();
            return true;
        }
        catch (TException x) 
        {
            // log exception message (with call stacks 
            // and all InnerExceptions)
        }

        result = default(T);
        return false;
    }

    public static T Try<T>(Func<T> func, T defaultValue)
    {
        T result;
        if (Try(func, out result))
            return result;

        return defaultValue;
    }
}

Example:

int queueSize = Catching<MyParsingException>
    .Try(() => Parse(optionStr, "QueueSize"), 5);

If Parse throws a MyParsingException , queueSize will default to 5 , otherwise the returned value from Parse is used (or any other exception will propagate normally, which is usually what you want with an unexpected exception).

This helps to avoid breaking up the flow of the code, and also centralises your logging policy.

You can write specialised versions of this kind of exception wrapping for special cases, eg catching a particular set of three exceptions, or whatever.

For the extreme end of the spectrum of possible solutions, check out Aspect-Oriented-Programming techniques, and tools such as PostSharp or Microsoft Policy Injection Block . This way you can define an aspect that does something on exception and weave it into all places in your code that need it.

If you just want to log the exceptions' messages and items, without doing special processing in the catch block, you could create a Reflection-based Object logger, passing the Exception as an argument. Doing so, you don't have a lot of catch blocks.

And if you are the code's owner, you can put the logging procedure inside the MySpecialException's constructor, removing the catch's block and making the code cleaner.

You could have something like:

public static class ErrorHandler
{

    public static void HandleMyException(MyException myEx)
    {
        Debug.WriteLine(myEx.MyErrorString);
        throw;
    }

    public static void HandleException(Exception myEx)
    {
        Debug.WriteLine(e.ToString());
        throw;
    }

}

or, in this specific case, have a more generic function like:

public static class ErrorHandler
{

    public static void WriteAndThrow(string msg)
    {
        Debug.WriteLine(msg);
        throw;
    }

}

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