web-dev-qa-db-ja.com

管理対象リソースをクリーンアップするためのDispose()?

この答え で見つかりました、

コードでDispose/Finalizeパターンが使用されている場合は、FinalizeメソッドのアンマネージリソースとDisposeメソッドのマネージリソースをクリーンアップします。

そして後で私は この素晴らしい記事 を見つけて、ファイナライズして破棄し、それらについて明確なアイデアを得ました。記事には、概念を説明する次のコード(ページ3)があります。

_class Test : IDisposable
{
    private bool isDisposed = false;

    ~Test()
    {
       Dispose(false);
    }

    protected void Dispose(bool disposing)
    {
       if (disposing)
       {
          // Code to dispose the managed resources of the class
       }
       // Code to dispose the un-managed resources of the class

       isDisposed = true;
    }

    public void Dispose()
    {
       Dispose(true);
       GC.SuppressFinalize(this);
    }
}
_

しかし、その下には同じメモ(この質問の冒頭に含めた)が表示されます。

Dispose/Finalizeパターンマイクロソフトでは、アンマネージリソースを使用する場合は、DisposeとFinalizeの両方を実装することをお勧めします。正しいシーケンスは、開発者がDisposeを呼び出すことになります。開発者がDisposeメソッドの明示的な呼び出しを怠った場合でも、Finalize実装が実行され、オブジェクトがガベージコレクションされたときにリソースが解放されます。 Francesco Balenaは彼のブログに「Dispose/Finalizeパターンは、アンマネージリソース(アンマネージメモリを含む)を割り当てるアンマネージコードを呼び出し、リソースを解放するために最終的に使用する必要があるハンドルを返す場合にのみ使用する必要があります。自分のメンバーを破棄またはファイナライズした後、親のそれぞれのメソッドを呼び出すことにより、親オブジェクトに連鎖します。」 Dispose/Finalizeパターンがコードで使用されている場合は、Finalizeメソッドでアンマネージリソースを、Disposeメソッドでマネージリソースを単純にクリーンアップします。

今、私は再び混乱しています。記事全体とコードサンプルでは、​​アンマネージリソースをDispose()で解放する必要があることが示されています。しかし、そのコメントの関連性は何ですか?

編集:

この行が確認されたので:

コードでDispose/Finalizeパターンが使用されている場合は、Finalizeメソッドでアンマネージリソースを、Disposeメソッドでマネージリソースをクリーンアップします。

間違っています、私は編集しました この答え

22
Sharun

その非常にシンプルな参照してください。

  1. アンマネージリソースを扱っている場合-両方を実装しますDisposeFinalizeDisposeは、開発者がリソースを解放するために、不要になったとすぐに呼び出されます。 Disposeを呼び出すのを忘れた場合、Frameworkは独自のGCサイクルでfinalizeを呼び出します(通常、独自の甘い時間がかかります)。
  2. オブジェクトが使い捨てオブジェクトを内部で使用する場合-実装するタイプのオブジェクトへの参照を作成して保持している場合は、Dispose()を実装しますDispose()で、まだ破棄していません。
  3. 上記のいずれにも当てはまらない場合(アンマネージリソースを処理していないか、オブジェクトが使い捨てオブジェクトを内部で使用している)-その後、何もしません。 FinalizeDisposeも実装しないでください。

いくつかの古典的な例:

System.IO.FileStreamオブジェクトは、ファイルへのロック/ストリームハンドルを管理します。したがって、破棄とファイナライズの両方を実装します。開発者がそれを破棄した場合、他のプログラムはすぐにそれにアクセスできます。彼がそれを破棄するのを忘れた場合、フレームワークはそれをファイナライズし、GCサイクルの後半でハンドルを閉じます。

System.Text.StringBuilder管理されていないリソースはありません。したがって、ファイナライズを破棄する必要はありません。

パターンに関する限り、それが何を意味するか

// Code to dispose the managed resources of the class

そのクラス内のコンポーネントとして持っている.NETオブジェクトのDisposeメソッドを呼び出すことです

そして

// Code to dispose the un-managed resources of the class

生のハンドルとポインタを閉じる手段。ここに例を含む更新されたコードがあります

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (!isDisposed)
    {
      if (disposing)
      {
        // Code to dispose the managed resources of the class
        internalComponent1.Dispose();
        internalComponent2.Dispose();
      }

      // Code to dispose the un-managed resources of the class
      CloseHandle(handle);
      handle = IntPtr.Zero;   

      isDisposed = true;
    }
  }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
}

これは古い質問です 説明する

47
Guru Kara

Fooに確定的クリーンアップの恩恵を受けるリソースがあるが、ファイナライザで有効にクリーンアップできるリソースがない場合、IDisposableを実装する必要がありますが、Finalizeをオーバーライドしたり、デストラクタ。クラスが複数のリソースを保持し、ファイナライザで少なくとも1つをクリーンアップできる場合、ファイナライザでクリーンアップできる個別の各リソースを、独自のファイナライザ/デストラクタ搭載オブジェクト(保護されたネストされたクラス)、およびそれらのリソースを含むクラスは、ラッパーオブジェクトへの参照を保持する必要があります。これが完了すると、外部クラスは、Disposeメソッドを使用するクラスのパターンに適合しますが、ファイナライザ/デストラクタはありません。

4
supercat