web-dev-qa-db-fra.com

Quand devrais-je créer un destructeur?

Par exemple:

public class Person
{
    public Person()
    {
    }

    ~Person()
    {
    }
}

Quand dois-je créer manuellement un destructeur? Quand avez-vous eu besoin de créer un destructeur?

176
delete

MISE À JOUR: Cette question était l'objet de mon blog en mai 2015 . Merci pour la bonne question! Voir le blog pour une longue liste de mensonges que les gens croient généralement à propos de la finalisation.

Quand dois-je créer manuellement un destructeur?

Presque jamais.

Généralement, on ne crée un destructeur que lorsque votre classe conserve des ressources non gérées coûteuses qui doivent être nettoyées lorsque l'objet disparaît. Il est préférable d’utiliser le motif jetable pour s’assurer que la ressource est nettoyée. Un destructeur est donc essentiellement une assurance que si le consommateur de votre objet oublie de le jeter, la ressource sera toujours nettoyée. (Peut être.)

Si vous créez un destructeur , soyez extrêmement prudent et comprenez le fonctionnement du garbage collector . Les destructeurs sont vraiment étranges :

  • Ils ne courent pas sur votre fil; ils courent sur leur propre fil. Ne provoque pas de blocages!
  • Une exception non gérée lancée par un destructeur est une mauvaise nouvelle. C'est sur son propre fil; qui va l'attraper?
  • Un destructeur peut être appelé sur un objet après le constructeur démarre mais avant le constructeur termine. Un destructeur correctement écrit ne s'appuiera pas sur les invariants établis dans le constructeur.
  • Un destructeur peut "ressusciter" un objet, redonnant vie à un objet mort. C'est vraiment bizarre. Ne le fais pas.
  • Un destructeur peut ne jamais courir; vous ne pouvez pas compter sur l'objet programmé pour la finalisation. Ce sera probablement , mais ce n’est pas une garantie.

Presque rien de ce qui est normalement vrai n'est vrai dans un destructeur. Sois vraiment très prudent. Écrire un destructeur correct est très difficile.

Quand avez-vous eu besoin de créer un destructeur?

Lors du test de la partie du compilateur qui gère les destructeurs. Je n'ai jamais eu besoin de le faire dans le code de production. J'écris rarement des objets manipulant des ressources non gérées.

226
Eric Lippert

C'est ce qu'on appelle un "finaliseur", et vous ne devriez généralement en créer qu'une pour une classe dont l'état (c'est-à-dire: les champs) inclut des ressources non gérées (c'est-à-dire: les pointeurs vers les handles récupérés via des appels p/invoke). Cependant, dans .NET 2.0 et les versions ultérieures, il existe en fait un meilleur moyen de nettoyer les ressources non gérées: SafeHandle . Compte tenu de cela, vous ne devriez pratiquement plus jamais avoir besoin d’écrire un finaliseur.

17
Nicole Calinoiu

Vous n'en aurez besoin que si votre classe gère des ressources non gérées, telles que les descripteurs de fichiers Windows.

8
John Saunders

Il s’appelle destructeur/finaliseur et est généralement créé lors de l’implémentation du modèle Disposed.

C'est une solution de secours lorsque l'utilisateur de votre classe oublie d'appeler Dispose pour s'assurer que (éventuellement) vos ressources sont libérées, mais vous n'avez aucune garantie quant au moment où le destructeur est appelé.

Dans cette question de débordement de pile , la réponse acceptée montre correctement comment mettre en œuvre le modèle de disposition. Cela n'est nécessaire que si votre classe contient des ressources non gérées que le récupérateur de place ne parvient pas à nettoyer lui-même.

Une bonne pratique consiste à ne pas implémenter de finaliseur sans donner également à l'utilisateur de la classe la possibilité de disposer manuellement de l'objet pour libérer immédiatement les ressources.

3
Øyvind Bråthen

Lorsque vous disposez de ressources non gérées et que vous devez vous assurer qu'elles seront nettoyées lorsque votre objet disparaîtra. Un bon exemple serait les objets COM ou les gestionnaires de fichiers.

3
Vlad Bezden

J'ai utilisé un destructeur (uniquement à des fins de débogage) pour voir si un objet était en train d'être purgé de la mémoire dans le cadre d'une application WPF. Je ne savais pas si le ramasse-miettes était en train de purger réellement l'objet de la mémoire et c'était un bon moyen de vérifier.

2
Neil.Allen

Les destructeurs fournissent un moyen implicite de libérer des ressources non managées encapsulées dans votre classe. Ils sont appelés lorsque le GC les utilise et appellent implicitement la méthode Finalize de la classe de base. Si vous utilisez beaucoup de ressources non gérées, il est préférable de fournir un moyen explicite de libérer ces ressources via l'interface IDisposable. Consultez le guide de programmation C #: http://msdn.Microsoft.com/en-us/library/66x5fx1b.aspx

1
SpaceghostAli