class / struct

Références

L'actualité

Librairie

L'information

Finaliseurs

Les finaliseurs (également appelés destructeurs) servent à effectuer les derniers nettoyages nécessaires lorsqu'une instance de classe est collectée par le récupérateur de mémoire.

Notes

  • Les finaliseurs ne peuvent pas être définis dans des structs. Ils sont utilisés uniquement avec les classes.
  • Une classe ne peut avoir qu'un seul finaliseur.
  • Les finaliseurs ne peuvent pas être hérités ou surchargés.
  • Les finaliseurs ne peuvent pas être appelés. Ils sont appelés automatiquement.
  • Un finaliseur ne prend pas de modificateur et n'a pas de paramètre.

Par exemple, voici une déclaration de finaliseur pour la classe Car.

Un finaliseur peut aussi être implémenté en tant que définition de corps d'expression, comme l'illustre l'exemple suivant.

Le finaliseur appelle implicitement Finalize sur la classe de base de l'objet. Ainsi, un appel à un finaliseur est traduit implicitement en ce code :

Cela signifie que la méthode Finalize est appelée de manière récursive pour toutes les instances de la chaîne d'héritage, de la plus dérivée à la moins dérivée.

Les finaliseurs vides ne doivent pas être utilisés. Quand une classe contient un finaliseur, une entrée est créée dans la file d'attente Finalize Quand le finaliseur est appelé, le récupérateur de mémoire est appelé pour traiter la file d'attente. Un finaliseur vide entraîne une perte de performances inutile.

Le programmeur n'a aucun contrôle sur le moment où le finaliseur est appelé, car celui-ci est déterminé par le récupérateur de mémoire. Le récupérateur de mémoire recherche les objets qui ne sont plus utilisés par l'application. S'il considère qu'un objet peut être finalisé, il appelle le finaliseur (s'il y en a un) et libère la mémoire utilisée pour stocker l'objet.

Dans les applications .NET Framework (mais pas dans les applications .NET Core), les finaliseurs sont également appelés quand le programme se termine.

Il est possible de forcer le nettoyage de la mémoire en appelant Collect, mais la plupart du temps c'est à éviter car cela peut créer des problèmes de performances.

Utiliser des finaliseurs pour libérer des ressources

En général, C# ne nécessite pas autant de gestion de mémoire que quand vous développez avec un langage qui ne cible pas un runtime avec nettoyage de la mémoire. En effet, le récupérateur de mémoire .NET Framework gère implicitement l'allocation et la libération de la mémoire pour vos objets. Toutefois, quand votre application encapsule des ressources non managées, telles que des fenêtres, des fichiers et des connexions réseau, vous devez utiliser des finaliseurs pour libérer ces ressources. Quand l'objet peut être finalisé, le récupérateur de mémoire exécute la méthode Finalize de l'objet.

Libération explicite de ressources

Si votre application utilise une ressource externe coûteuse, nous vous recommandons également de proposer un moyen de libérer explicitement la ressource avant que le récupérateur de mémoire ne libère l'objet. Pour cela, vous devez implémenter une méthode Dispose à partir de l'interface IDisposable qui effectue le nettoyage nécessaire pour l'objet. Cela peut améliorer considérablement les performances de l'application. Même avec ce contrôle explicite des ressources, le finaliseur devient un dispositif de protection pour nettoyer les ressources si l'appel à la méthode Dispose a échoué.

Exemple

L'exemple suivant crée trois classes qui forment une chaîne d'héritage. La classe First est la classe de base, Second est dérivée de First, et Third est dérivée de Second. Toutes trois ont des finaliseurs. Dans Main, une instance de la classe la plus dérivée est créée. Quand le programme s'exécute, notez que les finaliseurs des trois classes sont appelés automatiquement, et dans l'ordre, de la plus dérivée à la moins dérivée.