44

.NET ガベージ コレクターは最終的にメモリを解放しますが、そのメモリをすぐに戻したい場合はどうすればよいでしょうか。MyClass呼び出すクラスで使用する必要があるコードは何ですか?

MyClass.Dispose()

の変数とオブジェクトによって使用されているすべてのスペースを解放しますMyClassか?

4

20 に答える 20

101

IDisposable は、メモリの解放とは関係ありません。IDisposable は、管理されていないリソースを解放するためのパターンです。メモリは間違いなく管理されたリソースです。

GC.Collect() を指すリンクは正しい答えですが、Microsoft .NET のドキュメントでは、この関数の使用は一般的に推奨されていません。

編集:この回答でかなりの量のカルマを獲得したので、.NET リソース管理の初心者が間違った印象を受けないように、詳しく説明する責任があると感じています。

.NET プロセス内には、マネージとアンマネージの 2 種類のリソースがあります。「マネージド」はランタイムがリソースを制御することを意味し、「アンマネージド」はプログラマーの責任であることを意味します。そして、今日の .NET で重要なマネージド リソースは、メモリだけです。プログラマーはランタイムにメモリを割り当てるように指示し、その後、いつメモリを解放できるかを判断するのはランタイムです。.NET がこの目的で使用するメカニズムはガベージ コレクションと呼ばれ、Google を使用するだけで、インターネット上で GC に関する多くの情報を見つけることができます。

他の種類のリソースの場合、.NET はそれらのクリーンアップについて何も知らないため、正しいことを行うにはプログラマーに依存する必要があります。この目的のために、プラットフォームはプログラマーに 3 つのツールを提供します。

  1. VB と C# の IDisposable インターフェイスと "using" ステートメント
  2. ファイナライザ
  3. 多くの BCL クラスで実装されている IDisposable パターン

これらの最初のものは、プログラマーがリソースを効率的に取得し、それを使用し、同じメソッド内ですべて解放することを可能にします。

using (DisposableObject tmp = DisposableObject.AcquireResource()) {
    // Do something with tmp
}
// At this point, tmp.Dispose() will automatically have been called
// BUT, tmp may still a perfectly valid object that still takes up memory

「AcquireResource」が (たとえば) ファイルを開き、「Dispose」がファイルを自動的に閉じるファクトリ メソッドである場合、このコードはファイル リソースをリークできません。ただし、「tmp」オブジェクト自体のメモリはまだ割り当てられている可能性があります。これは、IDisposable インターフェイスがガベージ コレクターにまったく接続されていないためです。メモリが解放されたことを確認したい場合はGC.Collect()、ガベージ コレクションを強制的に呼び出すしか方法がありません。

ただし、これはおそらく良い考えではないことを十分に強調することはできません。一般的には、ガベージ コレクターに本来の目的であるメモリの管理を任せる方がはるかに優れています。

リソースが長期間使用され、その寿命が複数のメソッドにまたがる場合はどうなりますか? 明らかに、"using" ステートメントはもはや適用されないため、プログラマーはリソースを使い終わったときに手動で "Dispose" を呼び出す必要があります。プログラマーが忘れたらどうなりますか?フォールバックがない場合、プロセスまたはコンピューターは、適切に解放されていないリソースを最終的に使い果たす可能性があります。

そこでファイナライザーの出番です。ファイナライザーは、ガベージ コレクターと特別な関係を持つクラスのメソッドです。GC は、その型のオブジェクトのメモリを解放する前に、まずファイナライザーに何らかのクリーンアップを行う機会を与えることを約束します。

したがって、ファイルの場合、理論的にはファイルを手動で閉じる必要はまったくありません。ガベージ コレクターが到達するまで待ってから、ファイナライザーに作業を任せることができます。残念ながら、ガベージ コレクターは非決定論的に実行されるため、これは実際にはうまく機能しません。ファイルは、プログラマが予想するよりもかなり長く開いたままになる場合があります。また、十分な数のファイルを開いたままにしておくと、追加のファイルを開こうとしたときにシステムが失敗する可能性があります。

ほとんどのリソースでは、これらの両方が必要です。「このリソースはこれで完了です」と言える規則が必要であり、手動で行うのを忘れた場合にクリーンアップが自動的に行われる可能性が少なくともある程度あることを確認したいと考えています。そこで「IDisposable」パターンの出番です。これは、IDispose とファイナライザーがうまく連携できるようにする規則です。IDisposableの公式ドキュメントを見ると、パターンがどのように機能するかを確認できます。

結論:本当にやりたいことは、メモリが解放されていることを確認することだけである場合、IDisposable とファイナライザーは役に立ちません。しかし、IDisposable インターフェイスは、すべての .NET プログラマーが理解しておくべき非常に重要なパターンの一部です。

于 2008-08-15T15:40:33.567 に答える
23

IDisposable インターフェイスを実装するインスタンスのみを破棄できます。

ガベージ コレクションで (管理されていない) メモリをすぐに解放するには、次のようにします。

GC.Collect();  
GC.WaitForPendingFinalizers();

これは通常は悪い習慣ですが、たとえば、x64 バージョンの .NET フレームワークにバグがあり、シナリオによっては GC の動作がおかしくなることがあります。バグがまだ解決されているかどうかはわかりません。誰か知っていますか?

クラスを破棄するには、次のようにします。

instance.Dispose();

またはこのように:

using(MyClass instance = new MyClass())
{
    // Your cool code.
}

これは、コンパイル時に次のように変換されます。

MyClass instance = null;    

try
{
    instance = new MyClass();        
    // Your cool code.
}
finally
{
    if(instance != null)
        instance.Dispose();
}

次のように IDisposable インターフェイスを実装できます。

public class MyClass : IDisposable
{
    private bool disposed;

    /// <summary>
    /// Construction
    /// </summary>
    public MyClass()
    {
    }

    /// <summary>
    /// Destructor
    /// </summary>
    ~MyClass()
    {
        this.Dispose(false);
    }

    /// <summary>
    /// The dispose method that implements IDisposable.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// The virtual dispose method that allows
    /// classes inherithed from this one to dispose their resources.
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources here.
            }

            // Dispose unmanaged resources here.
        }

        disposed = true;
    }
}
于 2008-08-15T15:48:42.957 に答える
19

この質問への回答は、かなり混乱しています。

タイトルは廃棄について尋ねていますが、すぐにメモリを取り戻したいと言っています。

.Net は管理されています。つまり、.Net アプリを作成するときにメモリを直接気にする必要はありません。コストは、メモリを直接制御できないことです。

.Net コーダーであるあなたではなく、.Net がメモリをクリーンアップして解放するのが最適な時期を決定します。

これDisposeは、何かが完了したことを .Net に伝える方法ですが、そうするのに最適な時期になるまで、実際にはメモリを解放しません。

基本的に、.Net は、最も簡単にメモリを回収できるときに、実際にメモリを回収します。非常にメモリを集中的に使用するものを書いていない限り、通常は無視する必要はありません (これは、ゲームがまだ .Net で書かれていないことが多い理由の 1 つです。完全な制御が必要です)。

.Net では、すぐに強制するために使用できますGC.Collect()が、ほとんどの場合、これは悪い習慣です。.Net がまだクリーンアップしていない場合は、それを行うのに特に適した時期ではないことを意味します。

GC.Collect().Net が処理済みとして識別するオブジェクトをピックアップします。それを必要とするオブジェクトを破棄していない場合、.Net はそのオブジェクトを保持することを決定する場合があります。これはGC.Collect()、使い捨てインスタンスを正しく実装した場合にのみ有効であることを意味します。

GC.Collect()IDisposable を正しく使用する代わりにはなりません。

したがって、Dispose とメモリは直接関係していませんが、関係がある必要はありません。正しく破棄すると、.Net アプリがより効率的になり、メモリの使用量が少なくなります。


.Net では 99% の場合、以下がベスト プラクティスです。

ルール 1:管理されていないものや実装されているものを扱わない場合はIDisposable 、Dispose について心配する必要はありません。

ルール 2: IDisposable を実装するローカル変数がある場合は、現在のスコープでそれを取り除くようにしてください。

//using is best practice
using( SqlConnection con = new SqlConnection("my con str" ) )
{
    //do stuff
} 

//this is what 'using' actually compiles to:
SqlConnection con = new SqlConnection("my con str" ) ;
try
{
    //do stuff
}
finally
{
    con.Dispose();
}

ルール 3:クラスに IDisposable を実装するプロパティまたはメンバー変数がある場合、そのクラスも IDisposable を実装する必要があります。そのクラスの Dispose メソッドでは、IDisposable プロパティを破棄することもできます。

//rather basic example
public sealed MyClass :
   IDisposable
{   
    //this connection is disposable
    public SqlConnection MyConnection { get; set; }

    //make sure this gets rid of it too
    public Dispose() 
    {
        //if we still have a connection dispose it
        if( MyConnection != null )
            MyConnection.Dispose();

        //note that the connection might have already been disposed
        //always write disposals so that they can be called again
    }
}

これは実際には完全ではないため、この例は封印されています。クラスを継承するには、次の規則に従う必要があるかもしれません...

ルール 4:クラスがアンマネージリソースを使用する場合は、IDisposeを実装し、ファイナライザーを追加します。

.Net はアンマネージリソースに対して何もできないため、ここではメモリについて説明します。クリーンアップしないと、メモリリークが発生する可能性があります。

Dispose メソッドは、マネージドリソースとアンマネージドリソースの両方を処理する必要があります。

ファイナライザーはセーフティ キャッチです。他の誰かがクラスのインスタンスを作成し、それを破棄できなかった場合でも、「危険な」アンマネージリソースが .Net によってクリーンアップされることを保証します。

~MyClass()
{
    //calls a protected method 
    //the false tells this method
    //not to bother with managed
    //resources
    this.Dispose(false);
}

public void Dispose()
{
    //calls the same method
    //passed true to tell it to
    //clean up managed and unmanaged 
    this.Dispose(true);

    //as dispose has been correctly
    //called we don't need the 

    //'backup' finaliser
    GC.SuppressFinalize(this);
}

最後に、ブール値フラグを取る Dispose のこのオーバーロード:

protected virtual void Dispose(bool disposing)
{
    //check this hasn't been called already
    //remember that Dispose can be called again
    if (!disposed)
    {
        //this is passed true in the regular Dispose
        if (disposing)
        {
            // Dispose managed resources here.
        }

        //both regular Dispose and the finaliser
        //will hit this code
        // Dispose unmanaged resources here.
    }

    disposed = true;
}

これがすべて整ったら、クラスのインスタンスを作成する他のマネージ コードは、他の IDisposable (ルール 2 および 3) のように扱うことができることに注意してください。

于 2008-08-31T09:56:24.013 に答える
14

dispose が常にメモリを参照するとは限らないことにも言及するのは適切でしょうか? ファイルへの参照などのリソースは、メモリよりも頻繁に破棄します。GC.Collect() は CLR ガベージ コレクターに直接関連しており、(タスク マネージャーで) メモリを解放する場合と解放しない場合があります。アプリケーションに悪影響を与える可能性があります (パフォーマンスなど)。

一日の終わりに、なぜすぐに記憶を取り戻したいのですか? 他の場所からのメモリ不足がある場合、ほとんどの場合、OS がメモリを取得します。

于 2008-08-15T15:41:02.803 に答える
6

この記事を見てください

Dispose パターン、IDisposable、および/またはファイナライザーの実装は、メモリが再利用されるときとはまったく関係ありません。代わりに、そのメモリを再利用する方法をGC に指示することと関係があります。Dispose() を呼び出すと、GC と対話することはありません。

GC は、(メモリ プレッシャーと呼ばれる) 必要があると判断した場合にのみ実行され、その後 (その場合にのみ) 未使用のオブジェクトのメモリの割り当てを解除し、メモリ スペースを圧縮します。

GC.Collect() を呼び出すこともできますが、非常に正当な理由 (ほとんどの場合 "決して" しない) がない限り、そうすべきではありません。このような帯域外収集サイクルを強制すると、実際には GC がより多くの作業を行うようになり、最終的にはアプリケーションのパフォーマンスが低下する可能性があります。GC コレクション サイクルの間、アプリケーションは実際にはフリーズ状態にあります。実行される GC サイクルが増えるほど、アプリケーションがフリーズする時間が長くなります。

また、ワーキング セットを解放するために実行できるネイティブの Win32 API 呼び出しもいくつかありますが、それを行う非常に正当な理由がない限り、それらを避ける必要があります。

ガベージ収集されたランタイムの背後にある全体的な前提は、ランタイムが実際のメモリをいつ割り当て/割り当て解除するかについて (それほど) 心配する必要がないということです。オブジェクトが要求されたときにクリーンアップする方法を知っていることを確認することだけを心配する必要があります。

于 2008-08-17T14:22:44.940 に答える
5

http://codingcraftsman.wordpress.com/2012/04/25/to-dispose-or-not-to-dispose/に、デストラクタと Dispose および Garbage コレクションの概要を書きました。

元の質問に答えるには:

  1. 記憶を管理しようとしないでください
  2. Dispose はメモリ管理ではなく、管理されていないリソース管理に関するものです
  3. ファイナライザーは Dispose パターンの生来の部分であり、管理対象オブジェクトのメモリ解放を実際に遅くします (既に Dispose されていない限り、Finalization キューに入らなければならないため)。
  4. GC.Collect は、一部の短命のオブジェクトをより長く必要としているように見せ、収集を遅くするため、良くありません。

ただし、GC.Collect は、パフォーマンスが重要なコード セクションがあり、ガベージ コレクションによってパフォーマンスが低下する可能性を減らしたい場合に役立ちます。あなたは前にそれを呼び出します。

それに加えて、このパターンを支持する議論があります。

var myBigObject = new MyBigObject(1);
// something happens
myBigObject = new MyBigObject(2);
// at the above line, there are temporarily two big objects in memory and neither can be collected

myBigObject = null; // so it could now be collected
myBigObject = new MyBigObject(2);

しかし、主な答えは、いじらない限り、ガベージ コレクションは機能するということです。

于 2012-05-02T22:13:37.387 に答える
3

「廃棄、ファイナライズ、およびリソース管理」に関するJoeDuffyによる完全な説明:

.NET Frameworkの存続期間の初期には、ファイナライザーは一貫してC#プログラマーによってデストラクタと呼ばれていました。時間の経過とともに賢くなるにつれて、 Disposeメソッドは実際にはC ++デストラクタ(決定論的)と同等であり、 ファイナライザーは完全に別個のもの(非決定論的)であるという事実に同意しようとしています。C#がC ++デストラクタ構文(つまり〜T())を借用したという事実は、確かにこの誤称の開発と少なくとも少し関係がありました。

于 2008-08-26T09:36:18.907 に答える
3
public class MyClass : IDisposable
{
    public void Dispose()
    {
       // cleanup here
    }
}

次に、このようなことができます

MyClass todispose = new MyClass();
todispose.Dispose(); // instance is disposed right here

また

using (MyClass instance = new MyClass())
{

}
// instance will be disposed right here as it goes out of scope
于 2008-08-15T15:32:02.413 に答える
2

必要なときに GC にオブジェクトを強制的にクリーンアップさせることはできませんが、強制的に実行する方法はありますが、必要な/期待するすべてのオブジェクトをクリーンアップするとは言いません。try catch ex finally dispose end try (VB.NET rulz) の方法で dispose を呼び出すのが最善です。ただし、Dispose は、決定論的な方法でオブジェクトによって割り当てられたシステム リソース (メモリ、ハンドル、データベース接続など) をクリーンアップするためのものです。Dispose は、オブジェクト自体によって使用されるメモリをクリーンアップしません (できません)。それができます。

于 2008-08-15T15:42:36.217 に答える
1

@キース、

#4を除くすべてのルールに同意します。ファイナライザーの追加は、非常に特殊な状況でのみ行う必要があります。クラスが管理されていないリソースを使用する場合、それらはDispose(bool)関数でクリーンアップする必要があります。この同じ関数は、boolがtrueの場合にのみ管理対象リソースをクリーンアップする必要があります。ファイナライザーを追加すると、新しいインスタンスを作成するたびにオブジェクトをファイナライズキューに配置する必要があるため、オブジェクトの使用に複雑なコストが追加されます。ファイナライズキューは、GCが収集サイクルを実行するたびにチェックされます。事実上、これは、ファイナライザーを実行できるように、オブジェクトが本来よりも1サイクル/世代長く存続することを意味します。ファイナライザーは「セーフティネット」と考えるべきではありません。

GCは、GC.Collect()を呼び出して帯域外収集を強制することによって「支援」しない限り、Gen0ヒープに次の割り当てを実行するのに十分な使用可能なメモリがないと判断した場合にのみ収集サイクルを実行します。 。

つまり、GCは、Disposeメソッド(および、実装されている場合はファイナライザー)を呼び出すことによってリソースを解放する方法しか知りません。「正しいことを行い」、使用されている管理されていないリソースをクリーンアップし、他の管理されているリソースにDisposeメソッドを呼び出すように指示するのはそのメソッド次第です。それはそれが何をするかで非常に効率的であり、それが帯域外収集サイクルによって助けられない限り、大部分は自己最適化することができます。そうは言っても、GC.Collectを明示的に呼び出す以外に、オブジェクトを破棄してメモリを解放するタイミングと順序を制御することはできません。

于 2008-08-31T10:26:30.247 に答える
1

この記事には、かなり簡単なウォークスルーがあります。ただし、GC を自然な流れに任せずに呼び出さなければならないことは、一般に、設計/メモリ管理が不適切であることを示しています。特に、限られたリソース (接続、ハンドル、その他 IDisposable の実装につながるもの) が消費されていない場合は特にそうです。

これを行う必要がある原因は何ですか?

于 2008-08-15T15:30:57.393 に答える
1

申し訳ありませんが、ここで選択した回答は正しくありません。その後何人かが述べているように、Dispose と IDisposable の実装は、.NET クラスに関連付けられたメモリを解放することとは何の関係もありません。これは主に、ファイルハンドルなどの管理されていないリソースを解放するために伝統的に使用されています。

アプリケーションは GC.Collect() を呼び出してガベージ コレクターによるコレクションを強制することができますが、これは実際には freachable キュー内の正しい世代レベルにあるアイテムにのみ影響します。そのため、オブジェクトへのすべての参照をクリアしても、実際のメモリが解放される前に GC.Collect() を数回呼び出す可能性があります。

あなたの質問では、すぐにメモリを解放する必要があると感じる理由を述べていません。異常な状況が発生する場合があることは理解していますが、真剣に、マネージ コードでは、ほとんどの場合、ランタイムにメモリ管理を処理させることが最善です。

GC がメモリを解放するよりも早くコードがメモリを使い果たしていると思われる場合は、コードを見直して、静的メンバーなどにあるデータ構造で不要になったオブジェクトが参照されないようにする必要があります。また、循環オブジェクト参照が解放されない可能性があるため、このような状況も避けるようにしてください。

于 2008-08-25T21:29:10.013 に答える
0

@キース:

IDisposable はマネージド リソース用です。

ファイナライザーは、管理されていないリソース用です。

申し訳ありませんが、それは間違っています。通常、ファイナライザは何もしません。ただし、破棄パターンが正しく実装されている場合、ファイナライザーは を呼び出そうとしDisposeます。

Dispose次の 2 つのジョブがあります。

  • 管理されていないリソースを解放し、
  • ネストされた管理対象リソースを解放します。

そして、ここであなたのステートメントが登場します。これは、ファイナライズ中にオブジェクトがネストされた管理対象リソースを解放しようとしてはならないためです。これらはすでに解放されている可能性があるためです。ただし、管理されていないリソースを解放する必要があります。

Disposeそれでも、ファイナライザには、呼び出して、管理対象オブジェクトに触れないように指示する以外の仕事はありません。Disposeを手動で (または 経由でUsing) 呼び出すと、すべてのアンマネージ リソースを解放しDispose、ネストされたオブジェクト (および基本クラス メソッド) にメッセージを渡しますが、これによって(マネージ) メモリが解放されることはありません。

于 2008-08-26T09:11:17.703 に答える
0

Konrad Rudolph - ええ、通常、ファイナライザーは何もしません。管理されていないリソースを扱っていない限り、実装しないでください。

次に、それを実装するときは、Microsoft の破棄パターンを使用します(既に説明したように) 。

  • public Dispose()呼び出しprotected Dispose(true)- マネージド リソースとアンマネージド リソースの両方を扱います。呼び出しDispose()はファイナライズを抑制する必要があります。

  • ~Finalize呼び出しprotected Dispose(false)- 管理されていないリソースのみを扱います。これにより、呼び出しに失敗した場合のアンマネージ メモリ リークが防止されます。public Dispose()

~Finalize処理が遅いため、管理されていないリソースを処理する場合を除き、使用しないでください。

管理されたリソースはメモリ リークを起こすことができません。現在のアプリケーションのリソースを浪費し、そのガベージ コレクションを遅くすることしかできません。管理されていないリソースはリークする可能性があるため、リーク~Finalizeしないようにするためのベスト プラクティスです。

どちらの場合usingもベストプラクティスです。

于 2008-08-26T09:30:21.620 に答える
0

IDisposable インターフェイスは、実際にはアンマネージ リソースを含むクラス用です。クラスにアンマネージ リソースが含まれていない場合、ガベージ コレクターが解放する前にリソースを解放する必要があるのはなぜでしょうか。それ以外の場合は、オブジェクトができるだけ遅くインスタンス化され、できるだけ早く範囲外になるようにしてください。

于 2008-08-15T16:48:49.967 に答える
0

MyClass が IDisposable を実装している場合、それを行うことができます。

MyClass.Dispose();

C# でのベスト プラクティスは次のとおりです。

using( MyClass x = new MyClass() ) {
    //do stuff
}

これにより、dispose が try-finally にまとめられ、決して見逃されないようになります。

于 2008-08-15T15:32:40.337 に答える
0

クラスにIDisposableを実装したくない(または実装できない)場合は、このようにガベージコレクションを強制できます(ただし遅いです)-

GC.Collect();
于 2008-08-15T15:33:55.373 に答える
0

C ++で決定論的なオブジェクト破壊を行うことができます

GC.Collect を呼び出す必要はありません。GC.Collect は、メモリ不足を検出するためにガベージ コレクターの自己調整を妨害し、場合によっては、ヒープ上のすべてのオブジェクトの現在の世代を増やす以外に何もしません。

IDisposable の回答を投稿する場合。Dispose メソッドを呼び出しても、質問者が説明するようにオブジェクトは破棄されません。

于 2008-08-21T08:05:08.073 に答える
0

@Curt Hagenlocher - それは前に戻っています。間違っているのになぜ多くの人が投票したのか、私にはわかりません。

IDisposable管理対象リソース用です。

ファイナライザは、管理されていないリソース用です。

管理されたリソースのみを使用する限り、@Jon Limjap と私の両方が完全に正しいです。

管理されていないリソースを使用するクラス (.Net クラスの大部分は使用しないことに注意してください) の場合、Patrik の回答は包括的でベスト プラクティスです。

GC.Collect の使用は避けてください。管理されたリソースを処理するには時間がかかり、~Finalizers を正しく構築していない限り、管理されていないリソースには何もしません。


https://stackoverflow.com/questions/14593/e​​tiquette-for-modifying-posts に従って、元の質問からモデレーターのコメントを削除しました

于 2008-08-26T09:01:30.970 に答える
0

元の質問への回答として、元の投稿者によってこれまでに提供された情報を使用すると、彼が .NET でのプログラミングについて十分な知識を持っていないことは 100% 確実であり、GC.Collect() を使用して答えを得ることができます。ほとんどの投稿者が指摘しているように、彼が GC.Collect() をまったく使用する必要がない可能性は 99.99% です。

正解は、「GC に仕事を任せる」に要約されます。限目。他に気になることがあります。ただし、特定のオブジェクトを破棄またはクリーンアップする必要があるかどうか、いつ、クラスに IDisposable と Finalize を実装する必要があるかを検討することをお勧めします。

Keith の投稿と彼のルール #4 について:

ルール 3 とルール 4 を混同している投稿者もいます。Keith のルール 4 は絶対に正しいです。4 つのルールのうち、まったく編集する必要がないのは 1 つのルールです。彼の他のルールのいくつかをより明確にするために少し言い換えますが、それらを正しく解析し、実際に投稿全体を読んで、彼がそれらをどのように拡張するかを確認すれば、それらは本質的に正しいです.

  1. クラスがアンマネージ リソースを使用せず、それ自体がアンマネージ オブジェクト (つまり、IDisposable を実装するクラス) を直接または最終的に使用するクラスの別のオブジェクトをインスタンス化しない場合、そのクラスは必要ありません。 IDisposable 自体を実装するか、何かに対して .dispose を呼び出すことさえできます。(そのような場合、とにかく、強制GCですぐにメモリを解放する必要があると考えるのはばかげています。)

  2. クラスがアンマネージ リソースを使用する場合、またはそれ自体が IDisposable を実装する別のオブジェクトをインスタンス化する場合、クラスは次のいずれかを行う必要があります。

    a)これらが作成されたローカルコンテキストですぐに破棄/解放する、または...

    b) Keith の投稿内で推奨されているパターン、またはインターネット上の数千の場所、または現在までに文字通り約 300 冊の本で IDisposable を実装します。

    b.1) さらに、(b) で、それが開かれているアンマネージ リソースである場合、Keith のルール #4 に従って、IDisposable と Finalize の両方を常に実装する必要があります。
    このコンテキストでは、Finalize はある意味で完全にセーフティ ネットです。誰かがアンマネージド リソースを使用する YOUR IDisposable オブジェクトをインスタンス化し、dispose を呼び出せなかった場合、Finalize は YOUR オブジェクトがアンマネージド リソースを適切に閉じる最後のチャンスです。
    (Finalize は、Dispose メソッドがアンマネージ リソース以外の解放をスキップするような方法で Dispose を呼び出すことによってこれを行う必要があります。または、オブジェクトの Dispose メソッドがオブジェクトをインスタンス化したものによって適切に呼び出された場合は、両方とも Dispose 呼び出しをに渡します。インスタンス化されたすべての IDisposable オブジェクト、およびアンマネージ リソースを適切に解放し、オブジェクトの Finalize を抑制する呼び出しで終了します。ところで、キースの投稿に含まれています。)

    b.2) インスタンス化した IDisposable オブジェクトに Dispose を本質的に渡す必要があるため、クラスが IDisposable のみを実装している場合は、クラスに Finalize メソッドを実装しないでください。Finalize は、オブジェクトをインスタンス化したものによって Dispose が呼び出されず、まだ解放されていないアンマネージ リソースが使用された場合を処理するためのものです。

要するに、キースの投稿に関しては、彼は完全に正しいです。私の意見では、その投稿は最も正確で完全な答えです。彼は、一部の人が「間違っている」または反対する簡潔なステートメントを使用する可能性がありますが、彼の完全な投稿は Finalize の使用法を完全に拡張しており、彼は完全に正しいです。彼の投稿のルールや予備的な声明の 1 つにジャンプする前に、必ず彼の投稿を完全に読んでください。

于 2012-03-23T00:50:11.163 に答える