web-dev-qa-db-ja.com

オブジェクトがC#で破棄されたかどうかを確認する方法

可能性のある複製:
IDisposableオブジェクト参照が破棄されたかどうかをどのように確認しますか?

オブジェクトが別の方法で廃棄されているかどうかを確認する方法はありますか

_try
{
    myObj.CallRandomMethod();
} catch (ObjectDisposedException e)
{
    // now I know object has been disposed
}
_

私の場合、オブジェクトを破棄するClose()メソッドを持つTcpClientクラスを使用していますが、これは私が制御できないコードの一部で発生する可能性があります。この場合、例外をキャッチするよりも良い解決策が欲しいです。

65
jethro

TcpClientから派生させ、Disposing(bool)メソッドをオーバーライドするのが良い方法です。

class MyClient : TcpClient {
    public bool IsDead { get; set; }
    protected override void Dispose(bool disposing) {
        IsDead = true;
        base.Dispose(disposing);
    }
}

他のコードがインスタンスを作成した場合、これは機能しません。次に、Reflectionを使用してプライベートm_CleanedUpメンバーの値を取得するなど、必死なことを行う必要があります。または、例外をキャッチします。

率直に言って、これが非常に良い結果になりそうなことはありません。あなたは本当にdid TCP portに書きたい。しかし、あなたは制御できないバグのあるコードはyour code。バグの影響を大きくしました。そのコードの所有者と話をして何かを解決するのが最善の解決策です。

編集:リフレクションの例:

using System.Reflection;
public static bool SocketIsDisposed(Socket s)
{
   BindingFlags bfIsDisposed = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetProperty;
   // Retrieve a FieldInfo instance corresponding to the field
   PropertyInfo field = s.GetType().GetProperty("CleanedUp", bfIsDisposed);
   // Retrieve the value of the field, and cast as necessary
   return (bool)field.GetValue(s, null);
}
32
Hans Passant

信頼できる解決策は、ObjectDisposedExceptionをキャッチすることです。

Disposeメソッドのオーバーライドされた実装を記述するソリューションは、Disposeメソッドを呼び出すスレッドとオブジェクトにアクセスするスレッドとの間に競合状態があるため、機能しません。仮想IsDisposedプロパティをチェックした後、オブジェクトは実際に破棄される可能性があります、例外をすべてスローします。

別のアプローチは、仮説イベントDisposed( this など)を公開することです。これは、関心のあるすべてのオブジェクトにオブジェクトを破棄することを通知するために使用されますが、これはソフトウェア設計によっては計画するのが難しい場合があります。

27
Luca

オブジェクトが破棄されたかどうかわからない場合は、Disposeなどのメソッドではなく、Closeメソッド自体を呼び出す必要があります。フレームワークは、オブジェクトが以前に破棄された場合でも、Disposeメソッドが例外なく実行されることを保証しませんが、それは一般的なパターンであり、私の知る限り、フレームワーク内のすべての使い捨てオブジェクトに実装されています。

Microsoft によるDisposeの典型的なパターン:

public void Dispose() 
{
    Dispose(true);

    // Use SupressFinalize in case a subclass
    // of this type implements a finalizer.
    GC.SuppressFinalize(this);      
}

protected virtual void Dispose(bool disposing)
{
    // If you need thread safety, use a lock around these 
    // operations, as well as in your methods that use the resource.
    if (!_disposed)
    {
        if (disposing) {
            if (_resource != null)
                _resource.Dispose();
                Console.WriteLine("Object disposed.");
        }

        // Indicate that the instance has been disposed.
        _resource = null;
        _disposed = true;   
    }
}

_disposedのチェックに注意してください。このパターンを実装するDisposeメソッドを呼び出す場合、例外をヒットすることなく、必要な回数だけDisposeを呼び出すことができます。

16
Ryan Brunner

ベストプラクティスは、ローカルブールフィールドを使用して独自に実装することです: http://www.niedermann.dk/2009/06/18/BestPracticeDisposePatternC.aspx

0