Question

Something like:

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

I believe it is not a proper place for a return statement, is it?

Was it helpful?

Solution

As several others have pointed out in general this is not a problem.

The only case it will cause you issues is if you return in the middle of a using statement and additionally return the in using variable. But then again, this would also cause you issues even if you didn't return and simply kept a reference to a variable.

using ( var x = new Something() ) { 
  // not a good idea
  return x;
}

Just as bad

Something y;
using ( var x = new Something() ) {
  y = x;
}

OTHER TIPS

It's perfectly fine.

You are apparently thinking that

using (IDisposable disposable = GetSomeDisposable())
{
    //.....
    //......
    return Stg();
}

is blindly translated into:

IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();

Which, admittedly, would be a problem, and would make the using statement rather pointless --- which is why that's not what it does.

The compiler makes sure that the object is disposed before control leaves the block -- regardless of how it leaves the block.

It's absolutely fine - no problem at all. Why do you believe it's wrong?

A using statement is just syntactic sugar for a try/finally block, and as Grzenio says it's fine to return from a try block too.

The return expression will be evaluated, then the finally block will be executed, then the method will return.

This will work perfectly fine, just as returning in the middle of try{}finally{}

That is totally acceptable. A using statement ensures the IDisposable object will be disposed no matter what.

From MSDN:

The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler.

The code bellow shows how using is working:

private class TestClass : IDisposable
{
   private readonly string id;

   public TestClass(string id)
   {
      Console.WriteLine("'{0}' is created.", id);
      this.id = id;
   }

   public void Dispose()
   {
      Console.WriteLine("'{0}' is disposed.", id);
   }

   public override string ToString()
   {
      return id;
   }
}

private static TestClass TestUsingClose()
{
   using (var t1 = new TestClass("t1"))
   {
      using (var t2 = new TestClass("t2"))
      {
         using (var t3 = new TestClass("t3"))
         {
            return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
         }
      }
   }
}

[TestMethod]
public void Test()
{
   Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}

Output:

't1' is created.
't2' is created.
't3' is created.
'Created from t1, t2, t3' is created.
't3' is disposed.
't2' is disposed.
't1' is disposed.

The disposed are called after the return statement but before the exit of the function.

Perhaps it isn't 100% true that this is acceptable...

If you happen to be nesting usings and returning from within a nested one, it might not be safe.

Take this as an example:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
            return memoryStream.ToArray();
        }
    }
}

I was passing in a DataTable to be outputted as csv. With the return in the middle, it was writing all the rows to the stream, but the outputted csv was always missing a row (or multiple, depending on the size of the buffer). This told me that something wasn't being closed properly.

The correct way is to make sure all the previous usings are disposed properly:

using (var memoryStream = new MemoryStream())
{
    using (var textwriter = new StreamWriter(memoryStream))
    {
        using (var csv = new CsvWriter(textwriter))
        {
            //..write some stuff to the stream using the CsvWriter
        }
    }

    return memoryStream.ToArray();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top