usingステートメント内で例外がスローされた場合でも、Disposeは呼び出されますか?


103

以下の例では、接続がusingステートメント内にある場合、例外がスローされると接続が閉じて破棄されますか?

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    // stuff happens here and exception is thrown...
}

以下のこのコードがそれを確実にすることを知っていますが、ステートメントを使用してそれがどのように行われるのか知りたいです。

var conn;
try
{
    conn = new SqlConnection("...");
    conn.Open();
    // stuff happens here and exception is thrown...
}
// catch it or let it bubble up
finally
{
    conn.Dispose();
}

関連:

例外がスローされたときにSQL接続を確実に閉じるための適切な方法は何ですか?

回答:


112

はい、usingコードがtry / finallyブロックにラップされます。このブロックが存在する場合、そのfinally部分が呼び出さDispose()れます。ただし、実装さClose()れているIDisposableインターフェース、つまりDispose()メソッドをチェックするだけなので、直接呼び出すことはありません。

以下も参照してください。


5
接続クラスについてリフレクターを使用していることを指摘するだけで、Dispose()が実際に内部的にClose()を呼び出していることがわかります。それができる状態なら。
Chris Marisic

2
あなたは正しいです。ただし、これをIDisposableまたは関連するパターンに関係があると誰かに誤解させたくなかったので、意図的には触れませんでした。この特定の実装がClose()を呼び出すという事実は、パターンではなく、実装の詳細です。
ジェフ・イェーツ

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

20

これは、リフレクターがコードによって生成されたILをデコードする方法です。

プライベート静的void Main(string [] args)
{
    SqlConnection conn = new SqlConnection( "...");
    試す
    {
        conn.Open();
        DoStuff();
    }
    最後に
    {
        if(conn!= null)
        {
            conn.Dispose();
        }
    }
}

だから答えはイエスです、それは接続を閉じます

DoStuff()
例外をスローします。


conn.Open()が例外をスローした場合に追加します。:D
ジェフイエーツ

そうだね。using句が例外をスローした後にブロック内にあるものがあれば、接続は閉じられます。finallyブロックが実行されない唯一の方法は、 "new SqlConnection(...)"がスローする場合ですが、その場合、実際に有効な開いている接続を閉じることができません。だから大丈夫です。
Florin Sabau、

-1

このコードではDispose()は呼び出されません。

class Program {
    static void Main(string[] args) {
        using (SomeClass sc = new SomeClass())
        {
            string str = sc.DoSomething();
            sc.BlowUp();
        }
    }
}

public class SomeClass : IDisposable {
    private System.IO.StreamWriter wtr = null;

    public SomeClass() {
        string path = System.IO.Path.GetTempFileName();
        this.wtr = new System.IO.StreamWriter(path);
        this.wtr.WriteLine("SomeClass()");
    }

    public void BlowUp() {
        this.wtr.WriteLine("BlowUp()");
        throw new Exception("An exception was thrown.");
    }

    public string DoSomething() {
        this.wtr.WriteLine("DoSomething()");
        return "Did something.";
    }

    public void Dispose() {
        this.wtr.WriteLine("Dispose()");
        this.wtr.Dispose();
    }
}

これはOPの質問に答えますか?
ジョーイフィリップス

はい。答えはいいえだ。添付コードではDispose()は呼び出されません。さらに、スローされた例外は処理されず、プログラムが爆発します。
チャド

間違ったファイルを見ている必要があります。「Dispose()」が一時ファイルに書き込まれます。usingブロックが例外を処理するとは誰も主張していません。デバッガなしでこれを実行してみてください。
LarsTech

これとまったく同じコードを実行したところ、Dispose()が呼び出されました。あなたの答えは正しいですか?
Dnomyar96
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.