Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# try..catch - redirecting error handling flow from one catch to the next

Tags:

c#

try-catch

I have a try..catch block that looks like this:

try
{
    ...
}
catch (IOException ioEx)
{
    ...
}
catch (Exception ex)
{
    ... 
}

I'd like to handle just a certain kind of IOException, namely a sharing violation (Win32 0x20). Other IOExceptions and all other Exception descendants should be handled generally by the second catch-all catch.

Once I know that the IOException is not a sharing violation, how can I cleanly redirect the error handling flow to the general catch? If I rethrow in catch (IOException) the second catch does not invoke. I know I can nest try..catches but is there a cleaner way?

EDIT: On factoring-out handler logic

Factoring repeated code in methods will surely work, but I noticed that in general when you use factored methods for exception handling it tends to have subtle problems.

First of all, a catch clause has direct access to all of the local variables prior to the exception. But when you "outsource" exception handling to a different method then you have to pass the state to it. And when you change the code so does the handler method's signature changes, which might be a maintainability issue in more complicated scenarios.

The other problem is that program flow might be obscured. For example, if the handler method eventually rethrows the exception, the C# compiler and code analyzers like Resharper don't see it:

    private void Foo()
    {
        string a = null;

        try
        {
            a = Path.GetDirectoryName(a);
            System.Diagnostics.Debug.Print(a);
        }
        catch (Exception ex)
        {                
            HandleException(ex, a); //Note that we have to pass the "a"
            System.Diagnostics.Debug.Print(
                "We never get here and it's not obvious" + 
                "until you read and understand HandleException"
            );
            ...!
        }
    }

    static void HandleException(Exception ex, string a)
    {
        if (a != null)
            System.Diagnostics.Debug.Print("[a] was not null");
        throw (ex); //Rethrow so that the application-level handler catches and logs it
    }

VS

    private void Bar()
    {
        string a = null;

        try
        {
            a = System.IO.Path.GetDirectoryName(a);
            System.Diagnostics.Debug.Print(a);
        }
        catch (Exception ex)
        {                
            if (a != null)
                System.Diagnostics.Debug.Print("[a] was not null");
            throw; //Rethrow so that the application-level handler catches and logs it
            System.Diagnostics.Debug.Print(
                "We never get here also, but now " + 
                "it's obvious and the compiler complains"
            );
            ...!
        }
    }

If I want to avoid these kind of (minor) problems then it seems that there is no cleaner way than nesting try..catch blocks, as Hank pointed out.

like image 630
Boris B. Avatar asked May 27 '11 09:05

Boris B.


2 Answers

Just factor the handling logic into a separate method.

try
{
    ...
}
catch (IOException ioEx)
{
    if (sharing violation)
       HandleSharingViolation();
    else 
       HandleNonsharingViolation();
}
catch (Exception ex)
{
       HandleNonsharingViolation();
}

Or test the exceptions yourself

catch (Exception ex)
{
     if (ex is IOException && ex.IsSharingViolation()
       HandleSharingViolation();
     else
       HandleNonsharingViolation();
}
like image 122
Mongus Pong Avatar answered Oct 01 '22 20:10

Mongus Pong


No, you'll have to nest.

Once you are in 1 of the catch blocks, this 'try' is considered handled.

And I think it may make a lot of sense, "sharing violation" sounds like a special case that probably isn't so tightly coupled to the rest as you might be thinking. If you use nest try-catch, does the try block of the special case has to surround the exact same code? And of course it's a candidate to refactor out as a separate method.

like image 35
Henk Holterman Avatar answered Oct 01 '22 22:10

Henk Holterman