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 usi
I was looking for something similar for unit testing - I have a helper class I use to clean up objects after a test run and I want to keep the nice, clean 'using' syntax. I also wanted the option of not cleanup up if the test failed. What I came up with is to call Marshal.GetExceptionCode(). I don't know if this is appropriate for all cases, but for test code it seems to work fine.
The means of accomplishing this that I've seen require an extra method:
public static void MyMethod()
{
using (var scope = MyScopedBehavior.Begin())
{
//Do stuff with scope here
scope.Complete(); // Tells the scope that it's good
}
}
By doing this, your scope object can track whether it's disposing because of an error, or a successful operation. This is the approach taken by TransactionScope, for example (see TransactionScope.Complete).
As a side point, IL allows you to specify SEH fault
blocks that are similar to finally
but are entered only when an exception is thrown - you can see an example here, about 2/3rds down the page. Unfortunately, C# doesn't expose this functionality.
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:
public class Bling
{
public static void DoBling()
{
MyScopedBehavior.Begin(() =>
{
//Do something.
}) ;
}
}
public static class MyScopedBehavior
{
public static void Begin(Action action)
{
try
{
action();
//Do additonal scoped stuff as there is no exception.
}
catch (Exception ex)
{
//Clean up...
throw;
}
}
}
I think the best way is to use write out try/catch/finally
clause manually. Study an item from the first 'Effective c#" book. A good C# hacker should know exactly what using expands to. It has changed a bit since .Net 1.1 - you can now have several using one under another. So, use reflector, and study the un-sugared code.
Then, when you write your own code - either use the using
or write your own stuff. It is not terribly hard, and a good thing to know.
You could get fancy with other tricks, but it feels too heavy, and even not efficient. Let me include a code sample.
LAZY WAY:
using (SqlConnection cn = new SqlConnection(connectionString))
using (SqlCommand cm = new SqlCommand(commandString, cn))
{
cn.Open();
cm.ExecuteNonQuery();
}
MANUAL WAY:
bool sawMyEx = false;
SqlConnection cn = null;
SqlCommand cm = null;
try
{
cn = new SqlConnection(connectionString);
cm = new SqlCommand(commandString, cn);
cn.Open();
cm.ExecuteNonQuery();
}
catch (MyException myEx)
{
sawMyEx = true; // I better not tell my wife.
// Do some stuff here maybe?
}
finally
{
if (sawMyEx)
{
// Piss my pants.
}
if (null != cm);
{
cm.Dispose();
}
if (null != cn)
{
cn.Dispose();
}
}
It would be (IMHO very) helpful if there were a variant of IDisposable
whose Dispose
method accepted a parameter to indicate what exception, if any, was pending when it was run. Among other things, in the event that Dispose
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 a Dispose
method to throw an exception if code "forgets" to do something that it was supposed to do within a using
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 a try
which completed successfully, but that may be nested in a finally
block whose try
exited prematurely. Even if a Dispose
method could identify that such a situation existed, it would have no way of knowing which try
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
T Success<T>(T returnValue)
{
Success();
return T;
}
thus allowing code like:
return scopeGuard.Success(thingThatMightThrow());
rather than
var result = thingThatMightThrow();
scopeGuard.Success();
return result;