Is it possible to determine if code is currently executing in the context of a finally
handler as a result of an exception being thrown? I'm rather fond of using the IDisposable
pattern to implement entry/exit scoping functionality, but one concern with this pattern is that you might not necessarily want the end-of-scope behavior to occur if an exception occurs in the body of the using
. I'd be looking for something like this:
public static class MyClass
{
public static void MyMethod()
{
using (var scope = MyScopedBehavior.Begin())
{
//Do stuff with scope here
}
}
}
public sealed class MyScopedBehavior : IDisposable
{
private MyScopedBehavior()
{
//Start of scope behavior
}
public void Dispose()
{
//I only want to execute the following if we're not unwinding
//through finally due to an exception:
//...End of scope behavior
}
public static MyScopedBehavior Begin()
{
return new MyScopedBehavior();
}
}
There are other ways I can accomplish this (pass a delegate to a function that surrounds the call with particular behavior), but I'm curious if it's possible to do it using the IDisposable
pattern.
Actually, this has apparently been asked and answered before here. It's possible to detect in a very hackish sort of way. I wouldn't actually use that technique, but it's interesting to know that it's possible.
It would be (IMHO very) helpful if there were a variant of
IDisposable
whoseDispose
method accepted a parameter to indicate what exception, if any, was pending when it was run. Among other things, in the event thatDispose
is unable to perform the expected cleanup, it would be able to throw an exception which includes information about the earlier exception. It would also allow aDispose
method to throw an exception if code "forgets" to do something that it was supposed to do within ausing
block, but not overwrite any other exception that might cause the using block to exit prematurely. Unfortunately, no such feature exists as of yet.There are numerous articles which suggest means of using API functions to find out whether a pending exception exists. One major problem with such approaches is that it is possible that code may be running in a
finally
block for atry
which completed successfully, but that may be nested in afinally
block whosetry
exited prematurely. Even if aDispose
method could identify that such a situation existed, it would have no way of knowing whichtry
block it "belonged" to. One could formulate examples where either situation applies.As it is, the best approach is probably to have an explicit "success" method and assume failure if it's not called, and figure that the consequences of forgetting to call the "success" method should be obvious even if no exception is thrown. One thing that may be helpful as a simple utility method would be something like
thus allowing code like:
rather than
The following pattern avoids the problem with API misuse i.e. a scope completion method not being called i.e. omitted completely, or not being called because of a logical condition. I think this answers your question more closely and is even less code for the API user.
Edit
Even more straightforward after Dan's comment: