Returns a one-time object for use in the use block.

How to return a one-time object to my function to make sure that it works correctly in the using block? In my function, I want to work on a one-time object, and also take errors into account, which complicates this.

I have something similar to the following code:

 DBHandle GetDB() { /* // I can't do this, because the using block would dispose of my object within this function using( var db = DatabaseObj.GetHandle() ) { db.Open(); return db; } */ var db = DatabaseObj.GetHandle(); try { db.Open(); return db; } catch (Exception ex) { db.Dispose(); throw ex; } } // In other code: using( var obj = GetDB() ){ /* ... */ } 

Edit: I have outlined a more general question like this so as not to confuse the answers and discussions.

+2
c # idisposable using-statement
source share
5 answers

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)//not included if db is a value-type ((IDisposable)db).Dispose(); } } 

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.

+1
source share

Hint: when returning a one-time object from your use block, keep in mind that the Dispose () call is executed when the return statement is executed.

Thus, the object returned from the using block will already be deleted when it exits the function.

See the following code for an example.

 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class MyDisposable : IDisposable { public void DoSomething() { Console.WriteLine(" In DoSomething"); } #region IDisposable Members public void Dispose() { Console.WriteLine(" In Dispose"); } #endregion } class Program { static void Main(string[] args) { Console.WriteLine("Starting Main\n"); Console.WriteLine("Before NormalMethod"); NormalMethod(); Console.WriteLine("After NormalMethod\n"); Console.WriteLine("Before ReturningMethod"); MyDisposable m = ReturningMethod(); m.DoSomething(); // Here the object already has been disposed! Console.WriteLine("After ReturningMethod\n"); } private static void NormalMethod() { using (MyDisposable myDisposable = new MyDisposable()) { Console.WriteLine(" In NormalMethod"); } return; } private static MyDisposable ReturningMethod() { using (MyDisposable myDisposable = new MyDisposable()) { Console.WriteLine(" In ReturningMethod"); return myDisposable; } } } } 

This will lead to the following conclusion:

enter image description here

+4
source share

"Use" does your try / trick for you, just use db.Open; use will ensure that regardless of whether it throws away, it will use your connection.

+3
source share

If DBHandle implements IDisposable, then what you have should work.

There is no special way to return IDisposable.

+2
source share

The return value should simply implement IDisposable .

In practical terms, this statement should be true:

 IDisposable db = GetDB(); 

If this is compiled, you can put GetDB() in a using statement.

+1
source share

All Articles