user645280
user645280

Reputation:

Is there a way to chain double try/finally exceptions rather than losing or logging?

If my try throws, and my finally throws, how can I hold onto both exceptions, in a single chain, so that I can let them propagate up the stack naturally instead of requiring an intermediate logging facility?

I thought this might help:

Exception exCause = null;
try {
    // do something risky
} catch ( Exception ex ) {
    exCause = ex;
    throw;
} finally {
    //check for an important error condition
    // if error: throw new ApplicationException("finally failed", exCause);
}

But I wasn't sure if it might break something in the framework.

Obviously it still has the problem of two pre-existing exceptions that can't be merged if I call something that throws an exception in the finally, but I thought it might help a little bit to alleviate the need for every library in a system to have access to the same tracing routines.

Upvotes: 2

Views: 319

Answers (3)

supercat
supercat

Reputation: 81217

Neither C++, nor Java, nor .Net, has historically offered any good way of dealing with exceptions that occur in stack-unwinding cleanup code. This is unfortunate, because in many cases exceptions which occur in cleanup code are more important to the behavior of the program than exceptions which occur in main-line code, but are less helpful for diagnostic purposes (especially since a clean-up exception may occur as a result of a main-line exception).

It is possible in VB.net to write a try/finally block in such a way that the finally code will know what exception, if any, caused code to leave the try block, without claiming to catch or handle the exception in question. Unfortunately, that isn't possible in C# though it's possible for code in C# to achieve such an effect by calling a wrapper written in vb.net; the use of such a wrapper may be helpful even in vb.net since the code necessary to achieve the proper semantics is a bit icky. The using block in both languages could be improved if it could use an interface something like IDisposableDuringException { void Dispose(Exception ex);} which would be called if the Dispose was being executed during stack unwinding for an exception. That would allow code in the Dispose method to include the supplied exception in any exception that it might throw, and would also for the possibility of having dispose behavior vary based upon whether an exception was thrown (e.g. transaction scopes should clearly perform a rollback if they exit via exception--that's the point of them after all--but requiring them to implicitly perform a rollback when exited via normal means is icky).

With regard to what should happen if an exception is thrown during finally cleanup, I would suggest that whether or not an exception is pending, the proper behavior should be to throw something like a custom CleanupFailureException. Even if the calling code would have been prepared to catch e.g. InvalidOperationException thrown from the main-line, a successful completion of the main-line followed by an InvalidOperationException during cleanup will likely represent a situation different from the one the code was prepared to handle, and should thus use a different exception type.

Incidentally, there's often some debate about whether code should assume unexpected exceptions are fatal or non-fatal. I would posit that in many cases the proper approach would be to have stack unwinding from unexpected exceptions expressly invalidate the objects that were being worked with, such that all future operations with those objects will cause exceptions. This would have the effect that if an unexpected exception may corrupt a critically-important object the program may die off before doing any damage, but simultaneously allow for the possibility that if an exception corrupts an object which isn't going to be needed anyway (e.g. if an unexpected problem occurs while loading a document from a damaged file, and in the attempt to load the document the data structures associated with it got hopelessly corrupted, then if the code can abandon the partially-loaded document proceed sensibly without it, such corruption need not affect anything else.

Upvotes: 1

Sam Harwell
Sam Harwell

Reputation: 99949

This situation is best avoided by writing your finally handler in such a way that it won't throw an exception.

Upvotes: 3

Dave Lawrence
Dave Lawrence

Reputation: 3929

Maybe you could have a look at the System.AggregateException class

AggregateException is used to consolidate multiple failures into a single, throwable exception object.

http://msdn.microsoft.com/en-us/library/system.aggregateexception.aspx

That might help you

Upvotes: 3

Related Questions