tags:

views:

230

answers:

4

Here's an interesting question. I have a system that attempts to run some initialization code. If it fails, we call the deinitializer to clean everything up.

Because we call the deinitializer in exception handling, we run the risk that both initialize and deinitialize will fail, and hypothetically, it now seems that we have to throw two exceptions.

It seems pretty unlikely that we will, though. So what happens and what should the code do here?

   try { /* init code here */ }    
   catch (Exception ex)
   {
   try
   {
   _DeinitializeEngine();
   }
   catch (Exception ex2)
   {
   throw new OCRException("Engine failed to initialize; ALSO failed to deinitialize engine!", ex2);
   }
   finally
   {
   throw new OCRException("Engine failed to initialize; failed to initialize license!", ex);
   }
   }
+8  A: 

You shouldn't throw in the Finally block. Instead, use the InnerException to add information in the throw.

Update

What you have to do is to catch and rethrow with the "history" of exception, this is done with InnerException. You can edit it when bulding a new exception. This is a code snippet I just wrote to illustrate the idea that I explain in all the comments below.

    static void Main(string[] args)
    {
        try
        {
            principalMethod();
        }
        catch (Exception e)
        {
            Console.WriteLine("Test : " + e.Message);
        }
        Console.Read();
    }

    public static void principalMethod()
    {
        try
        {
            throw new Exception("Primary");
        }
        catch (Exception ex1)
        {
            try
            {
                methodThatCanCrash();
            }
            catch
            {
                throw new Exception("Cannot deinitialize", ex1);
            }
        }
    }

    private static void methodThatCanCrash()
    {
        throw new NotImplementedException();
    }

No need to use double throw with finalize. If you put a break point at the Console.WriteLine(...). You will notice that you have all the exception trace.

Daok
@Daok:He's throwing an exception if the first thing failed his "initialize" method. If that fails, but the "Deinitialize" succeeds, then he still wants to throw the first failed init exception.
BFree
Doesn't need to do it in the Finally. It will throw by itself if the _DeinitializeEngine() fail. The other catch (ex2) require an InnerException to not lost the first Exception...
Daok
Yea, but if the Init fails, but Deinit SUCCEEDS, then the only way to throw the first exception of the failed init method is in the finally.
BFree
no because you need to have the throw AFTER the _DeinitializeEngine() what ever it success or not because it has already fail.... I think you do not get my explication :P
Daok
OK, I'm sorry I didn't understand your English. My apologies. I see what you're saying now. You're saying to just throw the first exception in the try block itself after calling Deinit. IS that right?
BFree
I don't think this transmits both exceptions. Let's say we catch the exception on the outside. Which stack trace will we get?
Chris
One other thing - you can't write to InnerException. This is because InnerException is meant to identify the exception that *caused* the current exception. Using it to communicate a separate deinit exception is verboten.
Chris
You can thrown an Exception with in the constructor the inner exception so you just have to throw your new exception and pass by parameter the old exception...
Daok
See the code above, I just updated the answer. You will see what I am taking about.
Daok
You can do that, but you no longer get the exception thrown by the deinitialization method. At that point, it's not particularly useful to know that deinit failed; you can't get the stack trace or anything.
Chris
Deinit in my code corresponds to methodThatCanCrash in yours - we don't see that exception.
Chris
Where is the exception information for methodThatCanCrash()? We aren't seeing that information and definitely don't want to lose it.
Anderson Imes
+1  A: 

If I understand your problem correctly, here's what I would have done:

try { /* init code here */ }            
catch (Exception ex)
{
    // Passing original exception as inner exception
    Exception ocrex = new OCRException("Engine failed to initialize", ex);

    try
    {
        _DeinitializeEngine();
    }
    catch (Exception ex2)
    {
        // Passing initialization failure as inner exception
        ocrex = new OCRException("Failed to deinitialize engine!", ocrex);            
    }
    throw ocrex;
}
Luc Touraille
I think that version might be lacking something for ex2. And here we encounter the problem - trying to create a single exception out of two exceptions.
Chris
+1  A: 

If your clean up code is failing and you cannot leave the application in a clean and known state I would let the exception go unhandled (or catch it with the UnhandledException event to log it) then close the application.

Because if you can't handle the first exception, what point is there in catching the second exception?

Paul
A: 

You have two possible exception conditions: one in which the first method failed, and one in which both methods failed.

You're already defining your own exception class. So create another (or extend the first) with a RelatedException or PriorException property. When you throw the exception in the second case, save a reference to the first exception in this property.

It's up to the exception handler that catches this exception to figure out what to do with the second exception.

Robert Rossney