Quelle est la différence entre L'utilisation D'IDisposable vs un destructeur en C#?
quand mettrais-je en œuvre 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 collecteur d'ordures le fasse. Est-ce correct?
est-ce que cela signifie que je devrais toujours explicitement appeler Dispose sur un objet? Quels en sont les exemples courants?
7 réponses
un finalizer (alias destructor) fait partie de la collecte des ordures (CG) - il est indéterminé quand (ou même si) cela se produit, car CG se produit principalement en raison de la pression de la mémoire (c'est-à-dire besoin de plus d'espace). Les produits de finition ne sont habituellement utilisés que pour nettoyer les ressources non gérées , car les ressources gérées auront leur propre collecte ou élimination.
donc IDisposable
est utilisé pour de façon déterministe nettoyer des objets, c'est-à-dire maintenant. Il ne recueille 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 pour un objet IDisposable
d'avoir également un finalizer; dans ce cas, Dispose()
appelle habituellement GC.SuppressFinalize(this)
, ce qui signifie que GC ne lance pas le finalizer - il jette simplement la mémoire loin (beaucoup moins cher). Le finalizer fonctionne toujours si vous oubliez de Dispose()
l'objet.
le rôle de la méthode Finalize()
est de s'assurer qu'un objet .net peut nettoyer des ressources non gérées lorsque les déchets sont ramassés . Toutefois, les objets tels que les connexions aux bases de données ou les manipulateurs de fichiers devraient être libérés le plus tôt possible, plutôt que de dépendre de la collecte des ordures. Pour cela, vous devez implémenter IDisposable
interface, et libérer vos ressources dans la méthode Dispose()
.
il y a une très bonne description sur MSDN :
l'utilisation principale de cette interface est à libérer des ressources non gérées . Le collecteur d'ordures automatiquement libère la mémoire attribuée à un géré objet, pas de plus utilisé. Cependant, il est pas possible de prédire quand les ordures la collecte aura lieu . Outre, le ramasseur d'ordures n'a pas connaissance des ressources non gérées comme les poignées de fenêtre, ou ouvrir fichiers et flux.
utilisez la méthode D'élimination de ce interface avec release explicite 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.
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.
votre question à savoir si vous devez toujours appeler Dispose
est habituellement un débat houleux. Voir this blog pour une perspective intéressante de la part de personnes respectées dans la communauté.net.
personnellement, je pense que la position de Jeffrey Richter selon laquelle Dispose
n'est pas obligatoire est incroyablement faible. Il donne deux exemples pour justifier son opinion.
Dans le premier exemple, il dit appelant Dispose
sur les commandes de formulaires Windows est fastidieux et inutile dans les scénarios grand public. Cependant, il omet de mentionner que Dispose
est en fait appelé automatiquement par les conteneurs de contrôle dans ces scénarios grand public.
dans le deuxième exemple, il déclare qu'un développeur peut supposer à tort que l'instance de IAsyncResult.WaitHandle
devrait être disposé agressivement sans se rendre compte que la propriété initialise paresseusement la poignée d'attente résultant en un inutile les performances. Mais, le problème avec cet exemple est que le IAsyncResult
lui-même ne respecte pas les propres directives publiées par Microsoft pour traiter les objets IDisposable
. C'est-à-dire que si une classe contient une référence à un type IDisposable
, alors la classe elle-même devrait implémenter IDisposable
. Si IAsyncResult
suit cette règle alors sa propre méthode Dispose
pourrait prendre la décision concernant lequel de ses membres constitutifs doit disposer.
donc à moins que quelqu'un a un argument plus convaincant.je vais rester dans le camp "always call Dispose" avec la compréhension qu'il va y avoir des cas marginaux qui proviennent principalement de mauvais choix de conception.
c'est assez simple en fait. Je sais qu'il a été répondu, mais je vais réessayer, mais je vais essayer de rester aussi simple que possible.
un destructeur ne doit généralement jamais être utilisé. Ce n'est que run.net veut qu'il tourne. Il ne fonctionnera qu'après un cycle de collecte des ordures. Il se peut qu'il ne soit jamais utilisé pendant le cycle de vie de votre application. Pour cette raison, vous ne devriez jamais mettre tout le code dans un destructeur qui "doit" être exécuté. Vous ne pouvez pas compter sur des objets existants dans la classe à exister quand il fonctionne (ils peuvent avoir déjà été nettoyés car l'ordre dans lequel les destructeurs fonctionnent n'est pas garanti).
IDisposible devrait être utilisé chaque fois que vous avez un objet qui crée des ressources qui ont besoin de nettoyage (c'est-à-dire, des poignées de fichiers et de graphiques). En fait, beaucoup soutiennent que tout ce que vous mettez dans un destructeur devrait être Poutine IDisposable en raison des raisons énumérées ci-dessus.
la plupart des classes appelleront dispose lorsque le finalizer est exécuté mais ceci est simplement là comme un garde sûr et ne devrait jamais être comptée. Vous devez explicitement disposer de tout ce qui implémente IDisposable lorsque vous en avez fini avec elle. Si vous mettez en œuvre IDisposable, vous devriez appeler dispose dans finalizer. Voir http://msdn.microsoft.com/en-us/library/system.idisposable.aspx pour un exemple.
voici un autre bel article qui éclaircit une partie de la brume entourant IDisposable, le GC et dispose.