C#では、クラスのデストラクタとFinalizeメソッドの違いは何ですか?


96

クラスのデストラクタとFinalizeメソッドの違いは何ですか(ある場合)。

私は最近、Visual Studio 2008がデストラクタをFinalizeメソッドと同義と見なすことを発見しました。つまり、Visual Studioでは、クラスの両方のメソッドを同時に定義することはできません。

たとえば、次のコードフラグメント:

class TestFinalize
{
    ~TestFinalize()
    {
        Finalize();
    }

    public bool Finalize()
    {
        return true;
    }
}

デストラクタでFinalizeを呼び出すと、次のエラーが発生します。

呼び出しは次のメソッドまたはプロパティ間であいまいです: 'TestFinalize。〜TestFinalize()'と 'TestFinalize.Finalize()'

また、Finalizeの呼び出しがコメント化されている場合、次のエラーが発生します。

タイプ 'ManagementConcepts.Service.TestFinalize'は、同じパラメータータイプの 'Finalize'というメンバーを既に定義しています

回答:


68

C#のデストラクタはSystem.Object.Finalizeメソッドをオーバーライドします。あなたはする必要があり、そうするためにデストラクタ構文を使用します。手動で上書きFinalizeすると、エラーメッセージが表示されます。

基本的に、Finalizeメソッド宣言で実行しようとしいるのは、基本クラスのメソッドを非表示にすることです。これにより、コンパイラーは警告を発行します(警告が表示されたnew場合)。ここで注意すべき重要なことは、あなたがいることであることはできません両方overrideと宣言newデストラクタと両方あるので、同時に同じ名前を持つメンバーをFinalizeメソッドはエラーになります(ただし、あなたがすることができ、推奨されていないが、宣言しpublic new void Finalize()た場合の方法をデストラクタを宣言しているわけではありません)。


71

ウィキペディアでは、ファイナライザの記事でファイナライザとデストラクタの違いについていくつかの良い議論があります。

C#には、「真の」デストラクタはありません。構文はC ++デストラクタに似ていますが、実際にはファイナライザです。あなたはあなたの例の最初の部分でそれを正しく書いた:

~ClassName() { }

上記はFinalize関数の構文糖です。これにより、ベースのファイナライザーの実行が保証されますが、それ以外の点ではFinalize関数のオーバーライドと同じです。これは、デストラクタ構文を記述する場合、ファイナライザを実際に記述していることを意味します。

Microsoftよると、ファイナライザーはガベージコレクターが収集するときに呼び出す関数(Finalize)を指しますが、デストラクターは結果として実行されるコードのビット(になる構文上の砂糖Finalize)です。それらは、Microsoftが区別をしてはならないほど同じものに近いものです。

C ++ではオブジェクトが削除されるかスタックからポップされるとすぐに同じスレッドで実行され、C#では別のスレッドで別のスレッドで実行されるため、MicrosoftによるC ++の「デストラクタ」という用語の使用は誤解を招くものです。


デストラクタとファイナライザのこのような区別は、重要なものであると私は主張します。ただし、内部で何が行われているのかを気にする人だけが、この区別を気にするでしょう。
カイルバラン2014年

1
また、ECMA-334は、「デストラクタ」と「ファイナライザ」を明確に明確に明確にしていたことにも注意してください。MSがなぜ仕様の誤解を招く用語を依然として主張しているのか、私にはわかりません。
FrankHB 16

少なくともMonoでの作業から、C#は実際にはC ++をモデルにしており、ほとんどのネイティブC#オブジェクトはC ++オブジェクトです。Monoをコンパイルしたコンパイラの動作は、これらのC ++オブジェクトがどのように破壊されるか、そして同様に、C#オブジェクトのファイナライゼーションがC ++に伝達され、それらのデストラクタを呼び出す方法を指示します。区別は内部的には理にかなっていますが、C#自体にはまだ当てはまりません。
ケンジ

20

ここにあります:http://sanjaysainitech.blogspot.com/2007/06/difference-between-destructor-dispose.html

  1. デストラクタ

    これらは、オブジェクトのクリーンアップコードを含む特別なメソッドです。これらはGCによって暗黙的に呼び出されるため、コードで明示的に呼び出すことはできません。C#では、前に~記号が付いたクラス名と同じ名前になります。お気に入り-

    Class MyClass
    {
    
    ~MyClass()
    {
    .....
    }
    }

    VB.NETでは、デストラクタはSystem.ObjectクラスのFinalizeメソッドをオーバーライドすることによって実装されます。

  2. 廃棄

    これらはクラス内の他のメソッドと同じで、明示的に呼び出すことができますが、オブジェクトをクリーンアップするという特別な目的があります。disposeメソッドでは、オブジェクトのクリーンアップコードを記述します。データベース接続やファイルなど、disposeメソッドのすべてのアンマネージリソースを解放することが重要です。disposeメソッドを実装するクラスは、IDisposableインターフェイスを実装する必要があります。Disposeメソッドは、破棄するオブジェクトのGC.SuppressFinalizeメソッドを呼び出す必要があります。オブジェクトをクリーンアップする作業をすでに行っているため、クラスにはデストラクターがあり、ガベージコレクターがオブジェクトのFinalizeメソッドを呼び出す必要はありません。リファレンス:http : //msdn2.microsoft.com/en-us/library/aa720161(VS.71).aspx

  3. ファイナライズ

    Finalizeメソッドは、Disposeメソッドが呼び出されない場合に、リソースをクリーンアップするための保護手段として機能します。アンマネージリソースをクリーンアップするには、Finalizeメソッドのみを実装する必要があります。ガベージコレクターは管理対象リソースを自動的にクリーンアップするため、管理対象オブジェクトのFinalizeメソッドを実装しないでください。FinalizeメソッドはGCによって暗黙的に呼び出されるため、コードから呼び出すことはできません。

    注: C#では、Finalizeメソッドはオーバーライドできないため、内部実装がMSILのFinalizeメソッドをオーバーライドするデストラクタを使用する必要があります。VB.NETでは、Finalizeメソッドはデストラクタメソッドをサポートしているため、オーバーライドできます。

更新: 興味深いセミ関連スレッドはこちら


1
You should only implement a Finalize method to clean up unmanaged resources:ファイナライズに入れます。Disposeと同じですか?
hqt 2012年

@hqt:Disposeファイナライザを実装する必要がある場合をはるかに上回って実装する必要があるケース。Disposeクラスのインスタンスまたは派生クラスが、アンマネージリソースを直接所有するか、最後のものを直接所有してアンマネージリソースを直接所有するか、または最後に直接所有する最後のものを所有する可能性が高い場合に実装します。 etc. Finalizeリソースのクリーンアップのために実装するのは、自分のクラスが管理されていないリソースを<i>直接</ i>所有し、他にはほとんど何もない場合のみです。
スーパーキャット2012年

@hqt:クラスがアンマネージリソースを直接所有し、他のオブジェクトへの参照も保持する場合、アンマネージリソースは通常、独自のファイナライズ可能なクラス(理想的には、他のものへの強い参照を保持しない)に分割する必要があります。他のオブジェクトへの参照を保持するものは、リソース自体を所有するのではなく、「アンマネージリソースを直接所有するもの」のみを所有するため、ファイナライザは必要ありません。
スーパーキャット2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.