2009-07-02 26 views
74

Jaka jest różnica, jeśli taka istnieje, między destruktorem a metodą Finalize w klasie?W języku C# jaka jest różnica między destruktorem a metodą Finalize w klasie?

Niedawno odkryłem, że Visual Studio 2008 uważa destruktor za synonim metody Finalize, co oznacza, że ​​Visual Studio nie pozwoli ci jednocześnie zdefiniować obu metod w klasie.

Na przykład następujący fragment kodu:

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

    public bool Finalize() 
    { 
     return true; 
    } 
} 

daje następujący błąd na wezwanie do Finalizacja w destruktora:

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

A jeśli wywołanie Finalizacja jest wypowiedziało się, to wydaje następujący błąd:

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

Odpowiedz

52

Destruktor w języku C# zastępuje metodę System.Object.Finalize. Musisz mieć do użyć składni destruktor, aby to zrobić. Ręczne przesłonięcie Finalize spowoduje wyświetlenie komunikatu o błędzie.

Zasadniczo to, co próbujesz zrobić z deklaracją metody Finalize, to hiding metoda klasy bazowej. Spowoduje to, że kompilator wyda ostrzeżenie, które można wyciszyć za pomocą modyfikatora new (jeśli miało działać). Ważne jest, aby pamiętać, tutaj jest to, że nie możnazarówno override i zadeklarować new członek z identyczną nazwą w tym samym czasie więc uwzględniając zarówno destruktora i Finalize metody spowoduje wystąpienie błędu (ale może, chociaż niezalecane, zadeklaruj metodę public new void Finalize(), jeśli nie deklarujesz destruktora).

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.

Aktualizacja:Interesting semi-related thread here.

+0

'Należy zaimplementować metodę Finalize, aby wyczyścić niezarządzane zasoby': umieścisz ją w Finaliźcie. To samo z Dispose? – hqt

+0

@hqt: Przypadki, w których należy wdrożyć 'Dispose', znacznie przewyższają te, w których należy wdrożyć finalizator. Zaimplementuj polecenie "Usuń", jeśli jest prawdopodobne, że instancja klasy lub klasy pochodnej będzie ostatnią rzeczą, w której będzie bezpośrednio właścicielem niezarządzanego zasobu lub bezpośrednio będzie właścicielem ostatniej rzeczy, która będzie bezpośrednio właścicielem niezarządzanego zasobu, lub bezpośrednio będzie właścicielem ostatniej rzeczy do bezpośredniego posiadania itp. Zaimplementuj tylko 'Finalize' do czyszczenia zasobów, jeśli posiadasz klasę bezpośrednio posiadającą niezarządzany zasób i prawie nic innego - znacznie węższy scenariusz. – supercat

+0

@hqt: Jeśli jedna klasa będzie bezpośrednio właścicielem zasobów niezarządzanych, a także będzie zawierała odniesienia do innych obiektów, zasoby niezarządzane powinny być generalnie podzielone na własną klasę (która nie powinna zawierać żadnych silnych odniesień do innych elementów), co oznacza, że klasa, która zawiera odwołania do innych obiektów, posiadałaby jedynie "rzeczy, które bezpośrednio posiadają niezarządzane zasoby", zamiast posiadać same zasoby, a zatem nie potrzebowałaby finalizatora. – supercat

50

Wikipedia ma dobrą dyskusję na temat różnicy między finalizatorem a destructor w artykule finalizer.

C# naprawdę nie ma "prawdziwego" destruktora. Składnia przypomina destruktor C++, ale to naprawdę jest finalizator. Napisałeś go prawidłowo w pierwszej części swojej przykład:

~ClassName() { } 

Powyższe cukier syntaktyczny dla Finalize funkcji. Zapewnia to, że finalizatory w bazie są uruchomione, ale poza tym są identyczne z nadpisaniem funkcji Finalize. Oznacza to, że pisząc składnię destruktora, naprawdę piszesz finalizator.

According to Microsoft, Finalizer odnosi się do funkcji, która wywołuje śmieciarza kiedy zbiera (Finalize), podczas gdy destruktor jest Twój kawałek kodu, który wykonuje w wyniku (cukru składniowej, który staje Finalize). Są tak blisko tego, że Microsoft nie powinien był nigdy tego robić.

Używanie przez Microsoft pojęcia "destruktor" w C++ jest mylące, ponieważ w C++ jest ono wykonywane w tym samym wątku, gdy tylko obiekt zostanie usunięty lub znika ze stosu, podczas gdy w języku C# jest wykonywane w osobnym wątku pod adresem innym razem.

+0

Twierdzę, że takie rozróżnienie między destruktorem a finalizatorem jest ważne. Jednak tylko ci, którzy dbają o to, co dzieje się pod maską, będą dbać o to rozróżnienie. –

+0

Należy również zauważyć, że ECMA-334 jednoznacznie uwiarygodniało "destruktor" i "finalizator", dawno temu. Nie wiem, dlaczego MS nadal nalega na wprowadzający w błąd termin w swoich specyfikacjach. – FrankHB

+0

Przynajmniej z pracy z Mono, C# jest faktycznie modelowane po C++, a większość natywnych obiektów C# to obiekty C++. Sposób, w jaki kompilator kompilujący prace Mono dyktuje, jak te obiekty C++ są niszczone, i podobnie jak finalizacja obiektu C# propaguje się do C++ i wywołuje te destruktory. Rozróżnienie ma sens pod maską, ale nadal tak naprawdę nie dotyczy samego C#. – Kenzi