web-dev-qa-db-ja.com

IDisposable.Dispose()を安全に複数回呼び出す必要がありますか?

IDisposableの実装により、Dispose()を複数回安全に呼び出すことができますか?またはその逆?ほとんどの.NETFrameworkクラスに対してどのようなアプローチを取りますか?

具体的には、System.Data.Linq.DataContext.Dispose()を複数回呼び出しても安全ですか?

私が尋ねる理由は、この追加の保護が必要かどうか疑問に思っているからです。

_public override void Dispose(bool disposing)
{
    // Extra protection...
    if (this.obj != null)
    {
        this.obj.Dispose();
        this.obj = null;
    }

    // Versus simply...
    this.obj.Dispose();

    base.Dispose(disposing);
}
_

クラスのIDisposableメンバーを破棄するとき、または以前に呼び出されたかどうかを気にせずにthis.obj.Dispose()を呼び出す必要があるかどうか。

44
Jake Petroules

可能であれば回避する必要がありますが、複数回呼び出すのは安全です。

IDisposable.Dispose() のMSDNページから:

オブジェクトのDisposeメソッドが複数回呼び出された場合、オブジェクトは最初の呼び出し以降のすべての呼び出しを無視する必要があります。 Disposeメソッドが複数回呼び出された場合、オブジェクトは例外をスローしてはなりません。

60
Adam Robinson

はい、IDisposable.Dispose()の実装は、複数回呼び出されることを許容する必要があります。 Dispose()の最初の呼び出しの後、他のすべての呼び出しはすぐに戻ることができます。

コード例の最初の部分では、ローカル変数を破棄してnullにすることをお勧めします。

コードにDisposeパターンとnullパターンを実装している場合でも、.Dispose()が複数回呼び出される可能性があることに注意してください。複数のコンシューマーが同じ使い捨てオブジェクトへの参照を保持している場合、それらのコンシューマーがそのオブジェクトへの参照をドロップすると、そのオブジェクトのDisposeが複数回呼び出される可能性があります。

6
dthorpe

オブジェクトは、Disposeが複数回呼び出されることを許容する必要があります。これは、特に例外が存在する場合、クリーンアップコードがクリーンアップされたものとされていないものを確実に知ることが難しい場合があるためです。クリーンアップ時にIDisposableフィールドをnullにする(そしてすでにnullになっているフィールドを許容する)と、Disposeの冗長な呼び出しを回避するのが簡単になりますが、オブジェクトを複数の破棄に耐えさせるのに実際には何の費用もかかりません。いくつかの例外を投げる状況での不快感を避けてください。

2
supercat