Consider folowing classes:
class C1 : IDisposable {...}
class C2 : IDisposable {...}
sealed class C3 : IDisposable
{
public C3()
{
c1 = new C1();
throw new Exception(); //oops!
}
~C3()
{
//What can we do???
}
public void Dispose()
{
if ( c1 != null ) c1.Dispose();
if ( c2 != null ) c2.Dispose();
}
private C1 c1;
private C2 c2;
//assume that this class does not contains native resources
}
Now, assume we correctly use disposable object:
using (var c3 = new C3())
{
}
What about this code snippet?
In this case we can't call Dispose method, because our object never exists.
We know, that in this case finalizer would be called, but there we can dispose only CriticalFinilizedObjects and we can't dispose C1 or C2 objects.
My solution is pretty simple:
sealed class C3 : IDisposable
{
public C3()
{
try {
c1 = new C1();
throw new Exception(); //oops!
c2 = new C2();
}
catch(Exception)
{
DisposeImpl();
throw;
}
}
~C3()
{
//Not deterministically dispose detected!
//write to log!
//Invalid class usage. Or not??
}
public void Dispose()
{
DisposeImpl();
}
private void DisposeImpl()
{
if ( c1 != null ) c1.Dispose();
if ( c2 != null ) c2.Dispose();
GC.SuppressFinalize(this); //all resources are released
}
private C1 c1;
private C2 c2;
}
This solution may vary in some details but I think you can understand key principle: if constructor throws an exception we forcedly release acquired resources and suppress finalization.
Have any one other idias, suggestions or better solutions?
P.S. Herb Sutter in his blogpost (http://herbsutter.wordpress.com/2008/07/25/constructor-exceptions-in-c-c-and-java/) opened the question but he does not proposed a solution.