61


7

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

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

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

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

4 Answer


30


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ポートに書き込みたいです。 しかし、あなたは、あなたがコントロールできないバグのあるコードは、あなたのコードをコントロールするようになります。 バグの影響が大きくなりました。 そのコードの所有者と話をして何かを解決することは、間違いなく最善の解決策です。

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

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


25


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

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

別のアプローチは、Disposedオブジェクトに関する通知に使用される仮説イベントDisposed(http://msdn.microsoft.com/en-us/library/system.componentmodel.component.disposed.aspx[this]など)を公開することです。関心のあるすべてのオブジェクトに適用されますが、これはソフトウェア設計によっては計画するのが難しい場合があります。


16


オブジェクトが破棄されたかどうかわからない場合は、「Close」などのメソッドではなく、「Dispose」メソッド自体を呼び出す必要があります。 フレームワークは、オブジェクトが以前に破棄された場合でも、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を呼び出すことができます。


0


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