2009-03-19 9 views
144

何かの真ん中に戻っ:のような使用してブロック

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

私はそれがあり、それがreturn文のための適切な場所ではないと考えていますか?

答えて

149

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

問題が発生する唯一のケースは、usingステートメントの途中で戻り、in変数を追加して返す場合です。しかし、再び、これはあなたが帰ってこなくても変数への参照を保持していても問題を引き起こします。

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

同じように悪い

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

ちょうど私があなたが言及したポイントについて私の質問を編集しようとしていた。ありがとう。 – tafa

+0

なぜこれが悪いのか理解してください。私は、画像処理のためにヘルパー関数で使用しているストリームを別の関数に戻したいと思います。私がこれをしたら、ストリームが処分されるようですね? –

+1

@JohnShedletskyこの場合、関数呼び出しはを使用してラップする必要があります。 (Stream x = FuncToReturnStream()){...}を使用し、FuncToReturnStream内部では使用しません。 –

23

これはちょうど完全に許容可能であるtry{}finally{}

14

の真ん中に戻って、完全に正常に動作します。 ステートメントを使用すると、IDisposableオブジェクトが何であっても廃棄されることが保証されます。

MSDNから

usingステートメントは、廃棄は、あなたがオブジェクトのメソッドを呼び出している間に例外が発生した場合でも呼ばれていることを保証します。 tryブロックの中にオブジェクトを置き、finallyブロックでDisposeを呼び出すことで同じ結果を得ることができます。これは、usingステートメントがコンパイラによってどのように変換されるかです。

85

全く問題ありません。なぜそれが間違っていると思いますか?

usingステートメントはtry/finallyブロックの文法的な砂糖に過ぎません。また、Grzenioはtryブロックから戻っても問題ないと言っています。

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

+5

ジェームズ・カランの答えは、私が何を考えているかを説明しています。 – tafa

96

これは完璧です。

あなたは明らかに

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

を盲目的に翻訳されていることを考えている:

確かに、ある---問題となり、そして using文は、むしろ無意味になるだろう、
IDisposable disposable = GetSomeDisposable() 
//..... 
//...... 
return Stg(); 
disposable.Dispose(); 

なぜそれがではなく、なのですか?

コンパイラは、ブロックからどのように離れるかにかかわらず、コントロールがブロックを離れる前にオブジェクトが破棄されていることを確認します。

+5

私は、明らかにしていた。 – tafa

+0

素晴らしい答え@ジェームズ・カラン!しかしそれは、それが何に翻訳されているか私はむしろ好奇心が強いです。それとも、ILだけで表現できるのですか? (これまで私が読んでみたことはありませんでした)。 – Bart

+0

@Bart - 私は、戻り値の式を一時変数に評価した後、処分してから一時変数を返すと考えています。 – ToolmakerSteve

-3

おそらくこれは許容可能であることを100%真実ではありません...

あなたはusingsをネストし、ネストされた1つの中から戻ることが起こる場合それは安全ではないかもしれません。

は、一例として、これを持っ:

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

私はCSVファイルとして出力するのDataTableを渡しました。途中で復帰すると、すべての行がストリームに書き込まれていましたが、出力されたcsvには常に行が1つ(またはバッファのサイズによっては複数)欠落していました。これは、何かが適切に閉じられていないと私に言った。

正しい方法は、以前のすべてのusingsが適切に配置されていることを確認することです。

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

コード怒鳴るが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文の後で関数の終了前に呼び出されます。

関連する問題