2009-07-02 8 views
74

Was ist der Unterschied zwischen einem Destruktor und einer Finalize-Methode in einer Klasse, wenn es einen gibt?In C# Was ist der Unterschied zwischen einem Destruktor und einer Finalize-Methode in einer Klasse?

Ich habe kürzlich entdeckt, dass Visual Studio 2008 einen Destruktor als Synonym für eine Finalize-Methode ansieht, was bedeutet, dass Sie in Visual Studio nicht beide Methoden gleichzeitig in einer Klasse definieren können.

Zum Beispiel das folgende Codefragment:

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

    public bool Finalize() 
    { 
     return true; 
    } 
} 

gibt die folgenden Fehler auf dem Anruf im Destruktor finalisieren:

The call is ambiguous between the following methods or properties: 'TestFinalize.~TestFinalize()' and 'TestFinalize.Finalize()'

Und wenn der Anruf, es zu finalisieren kommentiert out gibt die folgende Fehlermeldung:

Type 'ManagementConcepts.Service.TestFinalize' already defines a member called 'Finalize' with the same parameter types

Antwort

52

Ein Destruktor in C# überschreibt System.Object.Finalize Methode. Sie müssen Destruktor-Syntax verwenden, um dies zu tun. Manuelles Überschreiben Finalize gibt Ihnen eine Fehlermeldung.

Grundsätzlich ist das, was Sie mit Ihrer Finalize Methodendeklaration zu tun versuchen, hiding die Methode der Basisklasse. Dies führt dazu, dass der Compiler eine Warnung ausgibt, die mit dem Modifikator new stummgeschaltet werden kann (falls es funktionieren würde). Wichtig ist hier zu beachten ist, dass Sie nicht beide override und ein new Mitglied mit identischen Namen in der gleichen Zeit erklären so sowohl eine destructor und ein Finalize Verfahren aufweist, wird in einem Fehler (aber Sie können , obwohl nicht empfohlen, deklarieren Sie eine public new void Finalize() Methode, wenn Sie keinen Destruktor deklarieren).

16

Found here: http://sanjaysainitech.blogspot.com/2007/06/difference-between-destructor-dispose.html

  1. Destructor

    They are special methods that contains clean up code for the object. You can not call them explicitly in your code as they are called implicitly by GC. In C# they have same name as the class name preceded by the ~ sign. Like-

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

    In VB.NET, destructors are implemented by overriding the Finalize method of the System.Object class.

  2. Dispose

    These are just like any other methods in the class and can be called explicitly but they have a special purpose of cleaning up the object. In the dispose method we write clean up code for the object. It is important that we freed up all the unmanaged recources in the dispose method like database connection, files etc. The class implementing dispose method should implement IDisposable interface.A Dispose method should call the GC.SuppressFinalize method for the object it is disposing if the class has desturctor because it has already done the work to clean up the object, then it is not necessary for the garbage collector to call the object's Finalize method. Reference: http://msdn2.microsoft.com/en-us/library/aa720161(VS.71).aspx

  3. Finalize

    A Finalize method acts as a safeguard to clean up resources in the event that your Dispose method is not called. You should only implement a Finalize method to clean up unmanaged resources. You should not implement a Finalize method for managed objects, because the garbage collector cleans up managed resources automatically. Finalize method is called by the GC implicitly therefore you can not call it from your code.

    Note: In C#, Finalize method can not be override, so you have to use destructor whose internal implementation will override the Finalize method in MSIL.But in the VB.NET, Finalize method can be override because it does support destructor method.

Update:Interesting semi-related thread here.

+0

'Sie sollten nur eine Finalize-Methode implementieren, um nicht verwaltete Ressourcen zu bereinigen': Sie setzen es in Finalize. Das gleiche gilt für Dispose? – hqt

+0

@hqt: Fälle, in denen "Dispose" implementiert werden sollte, sind weitaus größer als diejenigen, bei denen ein Finalizer implementiert werden sollte. Implementieren Sie "Dispose", wenn es wahrscheinlich ist, dass eine Instanz der Klasse oder einer abgeleiteten Klasse das letzte Ding ist, das direkt eine nicht verwaltete Ressource besitzt oder direkt das letzte besitzt, um direkt eine nicht verwaltete Ressource zu besitzen, oder direkt das letzte Ding besitzt direkt zu besitzen usw. Implementieren Sie 'Finalize' nur für die Ressourcenbereinigung, wenn die Klasse direkt eine nicht verwaltete Ressource besitzt und fast nichts anderes - ein viel engeres Szenario. – supercat

+0

@hqt: Wenn eine Klasse direkt nicht verwaltete Ressourcen besitzt und Referenzen auf andere Objekte enthält, sollten die nicht verwalteten Ressourcen in der Regel in ihre eigene finalisierbare Klasse aufgeteilt werden (die idealerweise keine starken Referenzen auf irgendetwas anderes enthalten sollte) Eine Klasse, die Verweise auf andere Objekte enthält, würde nur "Dinge besitzen, die direkt nicht verwaltete Ressourcen besitzen", anstatt die Ressourcen selbst zu besitzen, und würde somit keinen Finalizer benötigen. – supercat

50

Wikipedia hat eine gute Diskussion über den Unterschied zwischen einem Finalizer und einem destructor im finalizer Artikel.

C# hat wirklich keinen "wahren" Destruktor. Die Syntax ähnelt einem C++ - Destruktor, ist aber ein Finalizer. Sie schrieb es richtig im ersten Teil Ihres Beispiel:

~ClassName() { } 

Die obige syntaktischer Zucker für eine Finalize Funktion ist. Es stellt sicher, dass die Finalizer in der Basis ausgeführt werden, ist aber ansonsten identisch mit dem Überschreiben der Finalize-Funktion. Das heißt, wenn Sie die Destruktorsyntax schreiben, schreiben Sie wirklich den Finalizer.

According to Microsoft, bezieht sich der Destruktor die Funktion, die die Garbage Collector aufruft, wenn es (Finalize) sammelt, während die destructor Ihr Bit-Code ist, der als Ergebnis (den syntaktischen Zucker, die Finalize wird) ausführt. Sie sind so nahe daran, die gleiche Sache zu sein, die Microsoft nie hätte unterscheiden sollen.

Microsofts Verwendung des C++ "Destruktor" -Begriffs ist irreführend, da in C++ er in demselben Thread ausgeführt wird, sobald das Objekt gelöscht oder vom Stapel entfernt wird, während er in C# in einem separaten Thread bei ausgeführt wird einander mal.

+0

Ich würde argumentieren, dass eine solche Unterscheidung zwischen Destruktor und Finalizer eine wichtige ist. Aber nur diejenigen, die sich darum kümmern, was unter der Haube passiert, würden sich um diese Unterscheidung kümmern. –

+0

Beachten Sie auch, ECMA-334 hat formal "Destruktor" und "Finalizer" formal längst disambiguiert. Ich weiß nicht, warum MS immer noch auf den irreführenden Begriff in ihren Spezifikationen besteht. – FrankHB

+0

Zumindest aus der Arbeit mit Mono ist C# tatsächlich nach C++ modelliert, und die meisten nativen C# -Objekte sind C++ - Objekte. Die Art und Weise, wie der Compiler, der Mono kompiliert, diktiert, wie diese C++ - Objekte zerstört werden, und in ähnlicher Weise, wie C# -Objektabschluss nach C++ weitergeleitet wird und diese Destruktoren aufruft. Die Unterscheidung macht unter der Haube Sinn, aber es gilt immer noch nicht wirklich für C# selbst. – Kenzi