1

データセットの破棄に関するこの投稿を読みましたが、デストラクタについてまだ質問があります。基本的に、データセット、データテーブル、およびデータビューを破棄する必要はないと投稿が言っていることは知っていますが、私のデータセットは大規模であるため、そのメモリをできるだけ早く解放したいと考えています。それで、私の質問は、オブジェクトの破棄メソッドが呼び出されたときにデータセットが破棄されても、デストラクタを含める必要がありますか? また、「ブール処理」が必要な理由をもう一度説明してください。

        public DEditUtil(DataSet dsTxData)
    {
        this.dsTxData = dsTxData;
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
                dsTxData.Dispose();

            disposed = true;
        }
    }

    ~DEditUtil()
    {
        Dispose(false);
    }
4

4 に答える 4

4

はい、一般に、次のいずれかが当てはまる場合は常に、完全な IDisposable パターンを実装する必要があります。

  1. クラスによってアンマネージ リソースが割り当てられている、または
  2. 実装する管理されたリソースがありますIDisposable(つまり、管理されていないリソースがあることを意味します)。

ファイナライザ (C++/C# で「デストラクタ」と呼ばれるものの一般的な CLR 用語) の存在は、何らかの理由で Dispose メソッドが呼び出されない場合を処理するためのものです。Dispose()public 内から呼び出されているか、ファイナライザー内から呼び出されているかを示す、保護されたメソッドに渡されるブール値Dispose

publicDisposeメソッドが呼び出されている場合、そのコール スタックは確定的です。dispose メソッドが直接呼び出されているためDispose、子オブジェクトのメソッド ( を含む) を安全に呼び出すことができます。

ファイナライザーの内部にいる場合、ガベージ コレクションも行われている他のオブジェクトで何が起こっているのかわかりません。一般に、ファイナライザー内からコントロールするマネージド オブジェクトのメソッドを呼び出すのは安全ではない場合があります。

したがって、ブール値は基本的に、「true の場合はすべてを破棄します。false の場合は管理されていないリソースのみを破棄し、他のユーザーは自分のリソースを処理できるようにします。」

于 2012-05-04T14:07:35.653 に答える
2

オブジェクトが使用するメモリDataSetは、コードによって参照されなくなるとすぐに、ガベージ コレクションに使用できるようになります。

ガベージ コレクターは、後で (不確定な) そのメモリをプログラムで使用できるようにします。

どちらも、デストラクタまたは への呼び出しの有無に依存しないDisposeため、答えはノーです。デストラクタは必要ありません。

于 2012-05-04T14:07:26.257 に答える
1

呼び出しの失敗をログに記録する以外の目的で、ユーザー作成クラスがファイナライザー (または C# デストラクタ) を使用することはほとんどありませんDispose。ファイナライザーがどのように機能するか、またファイナライザーが実行されるコンテキストについて何が保証されているか、または何が保証されていないかを詳しく調べていない限りDispose、ファイナライザー内で他のオブジェクトのメソッドを呼び出してはなりません。特に、オブジェクトのFinalize()メソッドが実行IDisposableされている場合、参照を保持しているオブジェクトは通常、次のカテゴリのいずれかに分類されます。

  1. 他の誰かがまだそのオブジェクトへの参照を持っていて、それが使用可能であることを期待しているので、`Dispose` を呼び出すのは良くありません。
  2. ファイナライザ スレッド コンテキスト内でオブジェクトを安全に破棄することはできないため、「Dispose」を呼び出すのは不適切です。
  3. Dispose ハンドラーが実行する意味のあることがあれば、オブジェクトは現在のオブジェクトを存続させます。現在のオブジェクトの `Finalize` メソッドが実行されているという事実は、もう一方のオブジェクトで `Dispose` を呼び出す必要がなくなったことを意味します (このシナリオはイベントで発生する可能性があります)。
  4. オブジェクトは既に `Finalize` メソッドが呼び出されているため、`Dispose` を呼び出すことはせいぜい不必要です。
  5. オブジェクトは `Finalize` メソッドが呼び出されるようにスケジュールされているため、`Dispose` を呼び出す必要はありません。

オブジェクトがメソッドIDisposable内の別のオブジェクトをクリーンアップする必要がある場合がいくつかありますが、そのような場合に適切に使用するのは難しく、不適切に使用すると、まったく使用しないよりも悪い傾向があります。とりわけ、通常、エンティティが を要求し、それを放棄する前に不当に呼び出しに失敗した場合にのみ実行されます。通常、バグのある消費者コードを適切に処理しようとするよりも、オブジェクトが放棄される前に適切に取得できるようにすることに努力を集中する方がよいでしょう。FinalizeFinalizeFinalizeIDisposableDisposeDispose

于 2012-05-04T19:29:14.763 に答える
1

いいえ、ここで他のメソッドを呼び出す必要はありません。これで十分です。 Disposeランタイムによって呼び出され、割り当てられたリソースを解放します。クリーンアップは、いつ、どのように行うかを GC に任せましょう。

メモリに非常に大きな問題がある場合は、 calを使用してガベージのコレクションを強制することができますGC.Collect()。通常はこれでうまくいきますが、そのように使用することは決して良い方法ではないため、可能な限り回避するようにしてください。

編集

コメントによると、あなたのケースでは実行フローに注意を払うことが重要です。DataSetクリーンアップはそうでない場合にのみdisposed==false行われdisposing == true、提供されたコードからは、コードからの esplicit 呼び出し中にのみケースになります。

于 2012-05-04T14:05:39.973 に答える