2009-07-02 6 views
74

Quelle est la différence, s'il y en a une, entre un destructeur et une méthode Finalize dans une classe?En C#, quelle est la différence entre un destructeur et une méthode Finalize dans une classe?

J'ai récemment découvert que Visual Studio 2008 considère un destructeur comme synonyme d'une méthode Finalize, ce qui signifie que Visual Studio ne vous permet pas de définir simultanément les deux méthodes dans une classe.

Par exemple, le fragment de code suivant:

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

    public bool Finalize() 
    { 
     return true; 
    } 
} 

donne l'erreur suivante sur l'appel à Finaliser dans le destructor:

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

Et si l'appel à Finaliser est commenté, il donne l'erreur suivante:

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

Répondre

52

Un destructeur en C# remplace la méthode System.Object.Finalize. Vous devez utiliser la syntaxe destructeur pour le faire. L'annulation manuelle Finalize vous donnera un message d'erreur.

Fondamentalement, ce que vous essayez de faire avec votre déclaration de méthode Finalize est hiding la méthode de la classe de base. Cela obligera le compilateur à émettre un avertissement qui peut être ignoré à l'aide du modificateur new (s'il devait fonctionner). La chose importante à noter ici est que vous ne pouvez pas à la fois override et déclarer un membre new ayant le même nom en même temps pour avoir à la fois une destructor et une méthode Finalize entraînera une erreur (mais vous le pouvez , bien que déconseillé, déclarez une méthode public new void Finalize() si vous ne déclarez pas de destructeur).

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.

Mise à jour:Interesting semi-related thread here.

+0

'Vous ne devez implémenter une méthode Finalize pour nettoyer les ressources non managées': vous l'avez mis dans Finalize. Idem avec Dispose? – hqt

+0

@hqt: Les cas où l'on devrait implémenter 'Dispose' sont largement plus nombreux que ceux où l'on devrait implémenter un finaliseur. Implémentez 'Dispose' s'il est probable qu'une instance de la classe ou d'une classe dérivée soit la dernière à posséder directement une ressource non gérée, ou à posséder directement la dernière chose pour posséder directement une ressource non gérée, ou posséder directement la dernière chose Pour mettre directement à jour Finalize pour le nettoyage des ressources si sa classe directement possède une ressource non gérée et presque rien d'autre - un scénario beaucoup plus étroit. – supercat

+0

@hqt: Si une classe possède directement des ressources non gérées et détient également des références à d'autres objets, les ressources non managées doivent généralement être divisées en leur propre classe finalisable (qui ne devrait idéalement contenir aucune référence), ce qui signifie Une classe qui détient des références à d'autres objets ne posséderait que des «choses qui possèdent directement des ressources non gérées», plutôt que de posséder les ressources elles-mêmes, et n'aurait donc pas besoin d'un finaliseur. – supercat

50

Wikipédia a une bonne discussion sur la différence entre un finaliseur et un destructor dans l'article finalizer.

C# n'a pas vraiment de "vrai" destructeur. La syntaxe ressemble à un destructeur C++, mais c'est vraiment un finalizer. Vous avez écrit correctement dans la première partie de votre exemple:

~ClassName() { } 

Ce qui précède est le sucre syntaxique pour une fonction Finalize. Il garantit que les finaliseurs de la base sont garantis, mais est identique à la fonction Finalize. Cela signifie que lorsque vous écrivez la syntaxe du destructeur, vous êtes en train d'écrire le finaliseur.

According to Microsoft, le finaliseur fait référence à la fonction que le garbage collector appelle quand il recueille (Finalize), tandis que le destructor est votre morceau de code qui exécute en conséquence (le sucre syntaxique qui devient Finalize). Ils sont si près d'être la même chose que Microsoft n'aurait jamais dû faire la distinction.

L'utilisation par Microsoft du terme «destructeur» du C++ est trompeuse car, en C++, il est exécuté sur le même thread dès que l'objet est supprimé ou retiré de la pile, alors qu'en C# il est exécuté sur un thread distinct. une autre fois.

+0

Je dirais qu'une telle distinction entre le destructeur et le finaliseur est importante. Cependant, seuls ceux qui se soucient de ce qui se passe sous le capot se soucient de cette distinction. –

+0

Notez également ECMA-334 explicitement désambiguïsés "destructeur" et "finalizer" formellement, il y a longtemps. Je ne sais pas pourquoi MS insiste toujours sur le terme trompeur dans leurs spécifications. – FrankHB

+0

Au moins de travailler avec Mono, C# est réellement modélisé après C++, et la plupart des objets C# natifs sont des objets C++. La façon dont fonctionne le compilateur qui a compilé Mono dicte comment ces objets C++ sont détruits, et de même, comment la finalisation des objets C# se propage en C++ et appelle ces destructeurs. La distinction a du sens sous le capot, mais elle ne s'applique pas vraiment à C# lui-même. – Kenzi

Questions connexes