You have the right approach, but it seems a little lost as to how it is right.
Consider the code that you (correctly) say cannot work:
DBHandle GetDB() { using( var db = DatabaseObj.GetHandle() ) { db.Open(); return db; } }
This code is pretty much equivalent:
DBHandle GetDB() { var db = DatabaseObj.GetHandle(); try { db.Open(); return db; } finally { if(db != null)
It should be noted here that the attempt is not executed until after the assignment (the same is true for using - it will not save you from exceptions to the assignment in using ) and that db discarded to IDisposable , which means that it cannot compile if this assignment is unacceptable, and also that Dispose() can be either implicitly or explicitly implemented, and this will work anyway.
Now, of course, finally blocks will execute whether an exception is raised or not. You cannot use using because it is equivalent to finally and you want Dispose() in your method only if an exception occurs. Therefore, you take it completely and turn it into a catch:
DBHandle GetDB() { var db = DatabaseObj.GetHandle(); try { db.Open(); return db; } catch { if(db != null) ((IDisposable)db).Dispose(); throw; } }
This is almost the same as yours, except for adding a null check (maybe you can eliminate the need for it), and that I use a bare throw (it is usually a good idea when you will throw an exception again without changing or studying it In some cases, it is better to use a new exception, in which case you should include the original as an InnerException property of this new exception in order to provide additional information to someone to debug).
So, in general, you were on the right track. Hope I helped explain why.
Jon hanna
source share