16

使い方Dispose()とデストラクタについて質問があります。いくつかの記事と MSDN のドキュメントを読むと、これが推奨される実装方法Dispose()とデストラクタのようです。

しかし、この実装について 2 つの質問があります。以下をお読みください。

class Testing : IDisposable
{
    bool _disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed) // only dispose once!
        {
            if (disposing)
            {
                // Not in destructor, OK to reference other objects
            }
            // perform cleanup for this object
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);

        // tell the GC not to finalize
        GC.SuppressFinalize(this);
    }

    ~Testing()
    {
        Dispose(false);
    }
}

GC.SupressFinalize(this) on Dispose()

プログラマーusingが Dispose() を明示的に使用または呼び出すと、クラスは を呼び出しGC.SupressFinalize(this)ます。ここでの私の質問は次のとおりです。

  • これは正確には何を意味するのでしょうか? オブジェクトは収集されますが、デストラクタは呼び出されませんか? デストラクタはフレームワークによって Finalize() 呼び出しに変換されるため、答えはイエスだと思いますが、よくわかりません。

Dispose() 呼び出しなしでファイナライズする

GC がオブジェクトを消去しようとしているが、プログラマーが呼び出さなかったとします。Dispose()

  • この時点でリソースを処分しませんか? つまり、なぜデストラクタでリソースを解放できないのでしょうか?
  • if の内側と外側で実行する必要があるコードは何ですか?

    if (!_disposed) // only dispose once!
    {
       if (disposing)
       {
           //What should I do here and why?
       }
       // And what here and why?
    }
    

前もって感謝します

4

3 に答える 3

13

1. SuppressFinalizeは何をしますか?

ファイナライザリストからオブジェクトの登録を解除します。つまり、GCが後でオブジェクトを収集するときに、デストラクタの存在を無視します。デストラクタでは、オブジェクトのコレクションと、オブジェクトが参照するすべてのコレクションを遅延させる必要があるため、これはパフォーマンスの大幅な向上です。

2.この時点で[管理対象]リソースを破棄しないのはなぜですか?言い換えると、デストラクタで[管理された]リソースを解放できないのはなぜですか?

可能ですが、無意味であることは確かです。現在のオブジェクトが到達不能になっているため、所有されているすべての管理対象リソースも到達不能になっています。それらは同じ実行でGCによってファイナライズおよび収集され、それらに対してDispose()を呼び出す必要はありませんが、リスクやコストがまったくないわけではありません。

2a if内部でどのコードを実行する必要があり、どの外部で実行する必要がありますか?

内でif(disposing)、電話 _myField.Dispose()

つまり、管理対象リソース(Disposeを使用するオブジェクト)を破棄します。

外部では、コードを呼び出して、などの管理されていないリソースをクリーンアップ(クローズ)しWin32API.Close(_myHandle)ます。

管理されていないリソースがない場合(通常の場合(SafeHandleを検索))、デストラクタは必要ないため、SuppressFinalizeは必要ありません。

そしてそれは、このパターンの完全な(公式の)実装が必要なのは、Testが継承される可能性があるためだけです。が保護され
ていることに注意してください。Dispose(bool)クラスTestingをであると宣言する場合sealed、を省略することは完全に安全で適合してい~Testing()ます。

于 2011-01-06T13:21:49.607 に答える
2

最初の部分:

GC.SupressFinalize(this)呼び出されると、オブジェクトはすでにリソースを解放しており、他のオブジェクトと同様にガベージコレクションできることがGCに通知されます。そして、はい、ファイナライズと「デストラクタ」は.NETでは同じものです。

第二部:

ファイナライズは別のスレッドによって行われ、ファイナライズの時間と順序を制御できないため、他のオブジェクトがまだ使用可能であるか、すでにファイナライズされているかはわかりません。このため、disposingブロック外の他のオブジェクトを参照することはできません。

于 2011-01-06T13:23:05.537 に答える
1

リソースを所有するオブジェクトIDisposableがファイナライズされるほとんどの場合、次のステートメントの少なくとも 1 つがそれらのリソースのそれぞれに適用されます。

  1. すでにファイナライズされているため、クリーンアップは必要ありません。
  2. そのファイナライザーはまだ実行されていませんが、実行がスケジュールされているため、クリーンアップは必要ありません。
  3. 特定のスレッド (ファイナライザー スレッドではない) 内でのみクリーンアップできます。その場合、ファイナライザー スレッドはそれをクリーンアップしようとしてはなりません。
  4. 他の誰かがまだ使用している可能性があります。その場合、ファイナライザー スレッドはそれをクリーンアップしようとしてはなりません。

上記のいずれにも当てはまらないまれな状況では、ファイナライザー内でのクリーンアップが適切な場合がありますが、上記の 4 つの可能性を最初に調べていない限り、それを考慮すべきではありません。

于 2015-11-19T00:16:12.973 に答える