web-dev-qa-db-fra.com

Quelle est la différence entre utiliser IDisposable et un destructeur en C #?

Quand devrais-je implémenter IDispose sur une classe par opposition à un destructeur? J'ai lu cet article , mais je manque toujours le point.

Mon hypothèse est que si j'implémente IDispose sur un objet, je peux explicitement le "détruire" au lieu d'attendre que le garbage collector le fasse. Est-ce correct?

Est-ce à dire que je devrais toujours appeler explicitement Dispose sur un objet? Quels sont les exemples courants de cela?

95
Jordan Parmer

Un finaliseur (alias destructeur) fait partie de la collecte des ordures (GC) - il est indéterminé quand (ou même si) cela se produit, car GC se produit principalement en raison de la pression de la mémoire (c'est-à-dire besoin de plus d'espace). Les finaliseurs ne sont généralement utilisés que pour nettoyer les ressources non gérées , car les ressources gérées auront leur propre collection/élimination.

Par conséquent, IDisposable est utilisé pour de façon déterministe nettoyer les objets, c'est-à-dire maintenant. Il ne collecte pas la mémoire de l'objet (qui appartient toujours au GC) - mais est utilisé par exemple pour fermer des fichiers, des connexions de base de données, etc.

Il y a beaucoup de sujets précédents à ce sujet:

Enfin, notez qu'il n'est pas rare qu'un objet IDisposable ait également un finaliseur; dans ce cas, Dispose() appelle généralement GC.SuppressFinalize(this), ce qui signifie que GC ne lance pas le finaliseur - il jette simplement la mémoire (beaucoup moins cher). Le finaliseur fonctionne toujours si vous oubliez de Dispose() l'objet.

118
Marc Gravell

Le rôle de la méthode Finalize() est de garantir qu'un objet .NET peut nettoyer les ressources non managées lorsque les ordures sont collectées. Cependant, les objets tels que les connexions à la base de données ou les gestionnaires de fichiers doivent être libérés dès que possible, au lieu de s'appuyer sur le garbage collection. Pour cela, vous devez implémenter l'interface IDisposable et libérer vos ressources dans la méthode Dispose().

23
Igal Tabachnik

Il y a une très bonne description de MSDN :

L'utilisation principale de cette interface est de libérer des ressources non gérées . Le garbage collector libère automatiquement la mémoire allouée à un objet géré lorsque cet objet n'est plus utilisé. Cependant, il est impossible de prédire quand la collecte des ordures aura lieu . En outre, le garbage collector n'a aucune connaissance des ressources non gérées telles que les poignées de fenêtre ou les fichiers ouverts et les flux.

Utilisez la méthode Dispose de cette interface pour libérer explicitement les ressources non gérées conjointement avec le garbage collector. Le consommateur d'un objet peut appeler cette méthode lorsque l'objet n'est plus nécessaire.

9
abatishchev

La seule chose qui devrait être dans un destructeur C # est cette ligne:

Dispose(False);

C'est ça. Rien d'autre ne devrait jamais être dans cette méthode.

8
Jonathan Allen

Votre question de savoir si vous devez toujours appeler Dispose est généralement un débat houleux. Voir this blog pour une perspective intéressante de personnes respectées dans la communauté .NET.

Personnellement, je pense que la position de Jeffrey Richter selon laquelle appeler Dispose n'est pas obligatoire est incroyablement faible. Il donne deux exemples pour justifier son opinion.

Dans le premier exemple, il dit que l'appel de Dispose sur les contrôles Windows Forms est fastidieux et inutile dans les scénarios traditionnels. Cependant, il ne mentionne pas que Dispose est en fait appelé automatiquement par les conteneurs de contrôle dans ces scénarios traditionnels.

Dans le deuxième exemple, il déclare qu'un développeur peut supposer à tort que l'instance de IAsyncResult.WaitHandle doit être agressivement éliminé sans se rendre compte que la propriété initialise paresseusement la poignée d'attente, ce qui entraîne une pénalité de performance inutile. Mais, le problème avec cet exemple est que le IAsyncResult lui-même n'adhère pas aux propres directives publiées par Microsoft pour gérer les objets IDisposable. C'est-à-dire que si une classe contient une référence à un type IDisposable alors la classe elle-même doit implémenter IDisposable. Si IAsyncResult suivait cette règle, alors sa propre méthode Dispose pourrait prendre la décision concernant lequel de ses membres constituants devait être éliminé.

Donc, à moins que quelqu'un n'ait un argument plus convaincant, je vais rester dans le camp "appelez toujours Dispose" avec la compréhension qu'il y aura des cas marginaux qui découleront principalement de mauvais choix de conception.

4
Brian Gideon

C'est assez simple vraiment. Je sais qu'il a été répondu, mais je vais réessayer, mais je vais essayer de le garder aussi simple que possible.

Un destructeur ne doit généralement jamais être utilisé. Il est uniquement exécuté .net veut qu'il s'exécute. Il ne fonctionnera qu'après un cycle de récupération des ordures. Il peut ne jamais être exécuté pendant le cycle de vie de votre application. Pour cette raison, vous ne devez jamais mettre de code dans un destructeur qui "doit" être exécuté. Vous ne pouvez pas non plus compter sur des objets existants dans la classe pour exister lors de son exécution (ils peuvent avoir déjà été nettoyés car l'ordre dans lequel les destructeurs s'exécutent n'est pas garanti).

IDisposible doit être utilisé chaque fois que vous avez un objet qui crée des ressources qui doivent être nettoyées (c.-à-d. Les poignées de fichiers et de graphiques). En fait, beaucoup soutiennent que tout ce que vous mettez dans un destructeur devrait être mis en place pour des raisons énumérées ci-dessus.

La plupart des classes appellent disposer lorsque le finaliseur est exécuté, mais cela est simplement là en tant que garde et ne doit jamais être invoqué. Vous devez explicitement supprimer tout ce qui implémente IDisposable lorsque vous en avez terminé. Si vous implémentez IDisposable, vous devez appeler dispose dans le finaliseur. Voir http://msdn.Microsoft.com/en-us/library/system.idisposable.aspx pour un exemple.

2
DaEagle

Voici un autre bel article qui élimine une partie de la brume entourant IDisposable, le GC et élimine.

Chris Lyons WebLog démystifie l'élimination

0
scope_creep