web-dev-qa-db-ja.com

usingブロックの途中で戻る

何かのようなもの:

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

私はそれがreturnステートメントの適切な場所ではないと信じていますか?

174
tafa

他のいくつかが一般的に指摘しているように、これは問題ではありません。

問題を引き起こす唯一のケースは、usingステートメントの途中で戻り、さらにin using変数を返す場合です。しかし、これもまた、返さずに変数への参照を保持しただけでも問題が発生します。

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

同様に悪い

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

まったく問題ありません。

あなたはどうやら考えている

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

盲目的に翻訳されます:

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

確かに、これは問題になり、usingステートメントをかなり無意味にします---それがnotの理由です。

コンパイラは、オブジェクトがブロックを離れる方法に関係なく、制御がブロックを離れる前にオブジェクトが確実に破棄されるようにします。

125
James Curran

それは絶対に問題ありません-問題ありません。なぜそれが間違っていると思うのですか?

Usingステートメントは、try/finallyブロックの構文シュガーであり、Grzenioが言うように、tryブロックから戻ることもできます。

Return式が評価され、finallyブロックが実行され、メソッドが戻ります。

91
Jon Skeet

try{}finally{}の途中で戻るように、これは完全に正常に動作します

25
Grzenio

それは完全に受け入れられます。 usingステートメントは、IDisposableオブジェクトが何であれ破棄されることを保証します。

[〜#〜] msdn [〜#〜] から:

Usingステートメントは、オブジェクトのメソッドを呼び出しているときに例外が発生した場合でもDisposeが呼び出されるようにします。オブジェクトをtryブロック内に配置し、finallyブロックでDisposeを呼び出すことにより、同じ結果を得ることができます。実際、これはusingステートメントがコンパイラーによって変換される方法です。

16
mbillard

以下のコードは、usingの動作を示しています。

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());
}

出力:

「t1」が作成されます。
't2'が作成されます。
't3'が作成されます。
「t1、t2、t3から作成」が作成されます。
't3'は破棄されます。
't2'は破棄されます。
't1'は破棄されます。

破棄されるのは、returnステートメントの後、関数の終了前です。

10
Bertrand