質問

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

MyClass.Dispose()

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

役に立ちましたか?

解決

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

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

編集: この答えに対してかなりの量のカルマを獲得したので、.NET リソース管理の初心者が誤った印象を与えないように、これについて詳しく説明する一定の責任を感じています。

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

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

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

1 つ目では、プログラマは同じメソッド内でリソースを効率的に取得し、使用し、解放することができます。

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 プログラマが理解する必要がある非常に重要なパターンの一部です。

他のヒント

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

ガベージ コレクションを強制的に実行して (アンマネージド) メモリを直ちに解放するには、次のようにします。

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

これは通常は悪い習慣ですが、たとえば、x64 バージョンの .NET Framework には、シナリオによっては 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;
    }
}

この質問に対する答えは少なからず混乱しています。

タイトルでは廃棄について尋ねていますが、すぐに記憶を取り戻してほしいと述べています。

.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)。

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

結局のところ、なぜすぐに記憶を取り戻したいのでしょうか?他の場所からのメモリ負荷がある場合、ほとんどの場合、OS がメモリを取得します。

これをみて 記事

Dispose パターン、IDisposable、ファイナライザーの実装は、メモリがいつ回収されるかとは全く関係がありません。代わりに、GC に通知することにすべて関係しています。 どうやって その記憶を取り戻すために。Dispose() を呼び出すときは、GC と対話することはありません。

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

あなた できた GC.Collect() を呼び出しますが、実際には、 とても そうする十分な理由があります (これはほとんどの場合「決して」ではありません)。このように帯域外収集サイクルを強制すると、実際には GC の作業が増え、最終的にはアプリケーションのパフォーマンスに悪影響を及ぼす可能性があります。GC 収集サイクルの間、アプリケーションは実際にはフリーズ状態になります。実行される GC サイクルが増えるほど、アプリケーションがフリーズに費やす時間が長くなります。

ワーキング セットを解放するために実行できるネイティブ Win32 API 呼び出しもいくつかありますが、それらも、 とても それをする良い理由。

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

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

Joe Duffy による完全な説明」破棄、終了処理、およびリソース管理":

.NET FrameworkのLifetimeの前半では、ファイナライザーはC#プログラマーによって一貫してデストラクタと呼ばれていました。時間の経過とともに賢くなるにつれて、私たちは 処分方法は、C ++ Destructor(決定論的)に本当に相当します, 、一方、 ファイナルイザーは完全に別々のものです(非決定的). 。C#がC ++ Destructorの構文を借りたという事実(つまり〜t())は、この誤称の開発と少なくとも少し関係がありました。

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

元の質問に答えるには:

  1. 自分の記憶を管理しようとしないでください
  2. 破棄はメモリ管理ではなく、アンマネージド リソースの管理です
  3. ファイナライザは Dispose パターンの本質的な部分であり、管理対象オブジェクトのメモリ解放が実際に遅くなります (すでに Dispose されていない限り、ファイナライザはファイナライゼーション キューに入れられる必要があるため)。
  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);

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

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

この記事 非常に簡単なウォークスルーがあります。しかし、 持っている 自然な経過をたどらずに GC を呼び出すことは、通常、設計やメモリ管理が間違っていることを示しています。 特に 制限されたリソースが消費されていない場合 (接続、ハンドル、その他、通常 IDisposable の実装につながるもの)。

このようなことをする必要があるのはなぜですか?

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

アプリケーションは GC.Collect() を呼び出してガベージ コレクターによる強制的なコレクションを試みることができますが、これが実際に影響を与えるのは、到達可能なキュー内の正しい世代レベルにある項目に対してのみです。したがって、オブジェクトへの参照をすべてクリアした場合でも、実際のメモリが解放されるまでに GC.Collect() を数回呼び出す必要がある可能性があります。

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

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

@キース、

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

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

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

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

MyClass.Dispose();

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

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

これにより、try-finally で破棄が終了し、決して見逃されることがなくなります。

クラスに IDisposable を実装したくない (または実装できない) 場合は、次のようにガベージ コレクションを強制できます (ただし、時間がかかります)。

GC.Collect();

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

C++では決定論的なオブジェクトの破棄が可能です

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

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

@キース:

IDisposable は管理リソース用です。

ファイナライザーはアンマネージド リソース用です。

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

Dispose 2 つの仕事があります:

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

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

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

Konrad Rudolph - そうですね、通常、ファイナライザーは何も行いません。管理対象外のリソースを扱う場合を除き、これを実装しないでください。

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

  • public Dispose() 電話をかける protected Dispose(true) - 管理対象リソースと管理対象外リソースの両方を扱います。電話をかける Dispose() ファイナライゼーションを抑制する必要があります。

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

~Finalize は遅いため、管理対象外のリソースを処理する場合を除き、使用しないでください。

マネージド リソースはメモリ リークが発生せず、現在のアプリケーションのリソースを浪費し、ガベージ コレクションが遅くなるだけです。管理されていないリソースが漏洩する可能性があり、 ~Finalize そうならないようにすることがベストプラクティスです。

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

@Curt Hagenlocher – それは前から後ろへ。それが間違っているのに、なぜこれほど多くの人が賛成票を投じたのか分かりません。

IDisposable のためです 管理された リソース。

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

マネージドリソースのみを使用する限り、@Jon Limjapと私の両方が完全に正しいです。

アンマネージド リソースを使用するクラス (そして、大多数の .Net クラスは使用しないことに留意してください) については、Patrik の答えが包括的でベスト プラクティスです。

GC.Collect の使用は避けてください。これはマネージド リソースを処理する遅い方法であり、~Finalizer を正しく構築しない限り、アンマネージド リソースに対しては何も行いません。


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

元の質問に対する答えとして、元の投稿者がこれまでに提供した情報を考慮すると、彼が .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 の両方を常に実装する必要があります (SHOULD)。
    この文脈において、Finalize はある意味で間違いなくセーフティ ネットです。アンマネージド リソースを使用する IDisposable オブジェクトを誰かがインスタンス化し、dispose の呼び出しに失敗した場合、Finalize は、オブジェクトがアンマネージド リソースを適切に閉じる最後のチャンスです。
    (Finalize は、Dispose メソッドがアンマネージ リソース以外の解放をスキップするような方法で Dispose を呼び出すことによってこれを行う必要があります。あるいは、オブジェクトの Dispose メソッドが、オブジェクトをインスタンス化したものによって適切に呼び出されている場合は、インスタンス化したすべての IDisposable オブジェクトに Dispose 呼び出しを渡し、アンマネージ リソースを適切に解放し、オブジェクトの Finalize を抑制する呼び出しで終了します。これは、オブジェクトが呼び出し元によって適切に破棄された場合、Finalize を使用する影響が軽減されることを意味します。ところで、これらの点はすべて Keith の投稿に含まれています。)

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

つまり、キースの投稿に関しては、彼は完全に正しく、私の意見では、その投稿が最も正しく完全な答えです。彼は一部の人が「間違っている」と感じたり、反対したりするような短絡的な発言をしているかもしれませんが、彼の投稿全文は Finalize の使用法を完全に拡張しており、彼は完全に正しいです。彼の投稿内のルールや予備的な記述に飛びつく前に、必ず彼の投稿を最後まで読んでください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top