ISmartDisposable

time to read 3 min | 463 words

[Update: I create a ladybug suggestion for this, go vote for it]

I made some checking after this, by I seems that there isn't any way to tell whatever an exception occured when you're in a finally block. This is stupid, there are plenty of use cases where this is needed. Consider transactions, for instance:

using(Transaction transaction = session.EnterTransaction())
{
  // Do work with the transaction
  transaction.Commit();
}

Because when you're in the Transaction.Dispose() there is not way to know if an exception was thrown or not, you must call the transaction.Commit() so it would know what to do. This is very easy to forget and can cause problems because the code look correct.

I suggest a new interface:

public interace ISmartDisposable : IDisposable
{
  void Dipose(Exception exception);
}

And the previous using statement (without the transaction.Commit() ) would expand into something like this:

Transaction transaction = session.EnterTransaction();
ISmartDispose sd = transaction as ISmartDispose;
Exception exception = null;
try
{
  // do work
}
catch(Exception ex)
{
  exception = ex;
}
finally
{
 if (sd != null)//this line is s bug, removed
   sd.Dispose(exception); 
}

Now the transaction knows whatever an exception occured or not and can commit/rollback properly.  In the case of an object that implements IDisposable, the using statement should just fall back to the current behavior.

This is not just limited to transactions, and disposable object that need to know if an exception was raise can benefit from this. Rhino Mocks' MockRepsitory currently raise exceptions when the problem is locate elsewhere if an exception was raised by something other than the framework.

Considerring that this is merely a compiler constrcut, I'm thinking about implementing it in Boo.