IDisposableオブジェクト参照が破棄されているかどうかをどのように判断しますか?


88

廃棄されたオブジェクトへの参照であるかどうかを確認する方法、またはその他の軽量な方法はありますか?

PS-これは単なる好奇心です(本番コードではなく、よく眠れます)。はい、ObjectDisposedExceptionオブジェクトのメンバーにアクセスしようとすると、キャッチできることを知っています。


11
ダンノ。にbool IsDisposed { get; }宣言がないのは不思議なようSystem.IDisposableです。
nicodemus13 2012

3
@ nicodemus13:このDisposeメソッドは、取得したがまだ解放されていないすべてのリソースを解放するようにオブジェクトに指示します。オブジェクトがリソースを保持しない場合、そのDisposeメソッドは通常何もする必要はありません。タイプが宣言しvoid IDisposable.Dispose() {};ている場合は、IDisposableインスタンスごとのオーバーヘッドなしで無視できます。呼び出しのIsDisposed後にtrueになると予想されたプロパティではDispose、他の方法では無視できる多くのタイプのすべてのインスタンスに、それ以外の場合は不要なブールフラグを追加する必要がありますDispose
スーパーキャット2013

1
しかし、実装するオブジェクトのメソッドを呼び出す場合は常に、IDisposableそれが最初に破棄されたかどうかをどのように確認できますか?そうではないと想定して例外をキャッチするのではなく?それとも、どういうわけかあなたはそれが処分されているかどうかを常に知る必要があるように生涯を管理することを意図していますか?
nicodemus13 2013

3
@ nicodemus13:外部コードによるオブジェクトの破棄を、保留中のアクションを中止するシグナルと見なす準備ができている場合を除いて、オブジェクトが破棄されていないこと、および破棄されないことを知らずにオブジェクトを使用することは一般にできません。 。IsDisposedフラグは、おそらく成功することができない業務に時間を浪費するからコードを防ぐのに役立つかもしれませんが、一つは、まだオブジェクトが間に配置されます場合に例外を処理する必要がありますIsDisposedチェックし、それを使用しようとする試み。
スーパーキャット2015

WeakReferenceここに関連しているようです。これは正確にIDiposeされた検出器ではありませんが、GCされているかどうかはわかります
Malachi

回答:



42

System.Windows.Forms.Controlが呼び出され後にtrueに設定されるIsDisposedプロパティがあります。独自のIDisposableオブジェクトで、同様のプロパティを簡単に作成できます。Dispose()


OPは、自分が作成していないオブジェクトに同様のプロパティが既に存在するかどうかを確認しようとしていました。これは、作成するオブジェクトにとっては良い考えですが、.NETのほとんどの使い捨てクラスはこの規則に従っていません。ダンディカスの答えは正しいです。
krillgar 2014年

2
@ krillgar、OPの質問にはあなたの主張を裏付けるものは何もありません。
ライアンランディ2016年

19

これを可能にするものは何も組み込まれていません。内部のdisposedフラグを反映するIsDisposedブールプロパティを公開する必要があります。

public class SimpleCleanup : IDisposable
{
    private bool disposed = false;

    public bool IsDisposed
    {
       get
       {
          return disposed;
       }
    }

    public SimpleCleanup()
    {
        this.handle = /*...*/;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
               // free only managed resources here
            }

            // free unmanaged resources here
            disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
    }
}

ところで、このパターンの使用を開始する場合は、IDisposablePlusを継承しIDisposableて含む新しいインターフェイス(またはその他)を定義するのに役立ちますbool IsDisposed { get; }。これにより、どのIDisposableオブジェクトがサポートしているかを簡単に知ることができますIsDisposed
toolmakerSteve 2018年

C#の仕組みのせいで、インターフェイスを継承できるとは思いません。コロンの後にインターフェイスを配置すると、インターフェイスが継承されます。私はそれが他のインターフェースを実装することを期待しています。
モーゼス

9

それがあなたのクラスではなく、IsDisposedプロパティ(または同様のもの-名前は単なる慣例です)を提供しない場合、あなたは知る方法がありません。

ただし、それがクラスであり、正規のIDisposable実装に従っている場合は、_disposedまたは_isDisposedフィールドをプロパティとして公開して確認してください。


2

このDisposeメソッドは、オブジェクトが破棄される前に必要となるクリーンアップを実行するために必要です。クリーンアップが必要ない場合は、何もする必要はありません。Disposeメソッドが他の方法で何もしない場合でも、オブジェクトが破棄されたかどうかを追跡するようにオブジェクトに要求すると、IDisposable非常に限られた利点のために多くのオブジェクトがフラグを追加する必要があります。

IDisposable2つのプロパティが含まれていると便利だったかもしれません。1つはオブジェクトを破棄する必要があるかどうかを示し、もう1つはオブジェクトが破棄によって役に立たなくなっていないことを示します。廃棄が実際に何かを行うオブジェクトの場合、両方の値は最初はtrueであり、その後はfalseになりますDispose。廃棄でクリーンアップを行う必要がないオブジェクトの場合、フラグをどこにも格納しなくても、最初のメソッドは常にfalseを返し、2番目のメソッドは常にtrueを返す可能性があります。しかし、今はそれらを.NETに追加する方法はないと思います。


私見、2つの旗はやり過ぎです。オブジェクトに対してDisposeが呼び出されると、フラグが1つになるという、通常のパラダイムに固執する方がよいと思います。それ以外の場合は、Disposeが呼び出されたとしても、特定のオブジェクトが「まだ有用」であることを知るためだけに、複雑さを追加します。その道を行く価値はありません。
toolmakerSteve 2018年

@ToolmakerSteve:通常はゼロまたは1つのフラグがあります。廃棄が必要なオブジェクトの場合、「廃棄が必要」と「便利」のプロパティは、廃棄前に「true / true」、後で「false / false」を生成しますが、廃棄がノーオペレーションになるオブジェクトの場合、両方とも無条件に生成されます。 「false / true」を返します。オブジェクトが廃棄されないのに廃棄する必要がある、またはオブジェクトが常に廃棄されているのに役に立たないと言うのは、かなり厄介です。別のアプローチは、列挙型を使用して、型を破棄する必要があるか、破棄されたか、または単に気にしないかを示すことだと思います。
スーパーキャット2018年

@ToolmakerSteve:プロパティがIDisposableない大きな理由はDisposed、呼び出しDisposeによってそのようなプロパティが設定されないオブジェクトがあると奇妙に認識されtrueたと思いますが、オブジェクトDisposeが呼び出されたかどうかを追跡する必要がある場合そうでなければ、気にする理由がなく、かなりのコストがかかり、利益はほとんどありません。
スーパーキャット2018年

1

これは古いようですが、答えはわかりませんでした。DataSetのようなすべての使い捨てオブジェクトに、アタッチできる破棄イベントがあるわけではありません。

class DisposeSample : IDisposable
{
    DataSet myDataSet = new DataSet();
    private bool _isDisposed;

    public DisposeSample()
    {
        // attach dispose event for myDataSet
        myDataSet.Disposed += MyDataSet_Disposed;
    }

    private void MyDataSet_Disposed(object sender, EventArgs e)
    {
        //Event triggers when myDataSet is disposed
        _isDisposed = true; // set private bool variable as true 
    }


    public void Dispose()
    {
        if (!_isDisposed) // only dispose if has not been disposed;
            myDataSet?.Dispose(); // only dispose if myDataSet is not null;
    }
}

知っておくと良い。具体的には、DisposedイベントはSystem.ComponentModel.IComponentインターフェイスのメンバーです。
toolmakerSteve 2018年

-1

私がやりたいのは、オブジェクトを初期化せずに宣言することですが、デフォルト値をに設定しますNothing。次に、ループの最後に次のように記述します。

If anObject IsNot Nothing Then anObject.Dispose()

完全なサンプルは次のとおりです。

Public Sub Example()
    Dim inputPdf As PdfReader = Nothing, inputDoc As Document = Nothing, outputWriter As PdfWriter = Nothing

    'code goes here that may or may not end up using all three objects, 
    ' such as when I see that there aren't enough pages in the pdf once I open  
    ' the pdfreader and then abort by jumping to my cleanup routine using a goto ..

GoodExit:
    If inputPdf IsNot Nothing Then inputPdf.Dispose()
    If inputDoc IsNot Nothing Then inputDoc.Dispose()
    If outputWriter IsNot Nothing Then outputWriter.Dispose()
End Sub

これは、メインオブジェクトをルーチンの先頭にTry配置し、ルーチン内で使用して、Finallyブロックに配置する場合にも役立ちます。

Private Sub Test()
    Dim aForm As System.Windows.Forms.Form = Nothing
    Try
        Dim sName As String = aForm.Name  'null ref should occur
    Catch ex As Exception
        'got null exception, no doubt
    Finally
        'proper disposal occurs, error or no error, initialized or not..
        If aForm IsNot Nothing Then aForm.Dispose()
    End Try
End Sub

6
@LarsHöppner:質問の本質は言語に依存しないことです。優れたC#開発者は、少なくとも上記のコードを読み取るのに十分なVB.NETを知っている必要があります(VB.NET開発者も同様に、そうでないC#コードを読み取るのに十分なC#を学習する必要があります。特にエキゾチックなことは何でもしてください)。
スーパーキャット2013

3
Usingステートメントを使用する代わりに、なぜこれらすべてを行うのですか?それは確かにこの答えが書かれた2013年に存在していました。
コーディグレイ

本当に「GoodExit:」この1983年のGOTOは何ですか?使用をやめてください。
モーゼス

これは質問に答えません。具体的にinputPdfは、値(Nothing以外)に設定されると、あなたの答えは、inputPdf処分されたかどうかを知る方法を示しません。廃棄後に設定することで、これに部分的に対処できますinputPdf = Nothing。ただし、これは、と同じオブジェクトを指している他の変数には役立ちませんinputPdf。:それはあなたが行う場合で inputPdf = New PdfReaderDim pdf2 As PdfReader = inputPdfinputPdf.DisposeinputPdf = Nothing、まだそれは知っている方法はありませんpdf2(それは同じオブジェクトです配置されていますinputPdf)。
toolmakerSteve 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.