40 votes

Gestion des objets .NET IDisposable

Je travaille en C#, et j'ai été assez laxiste sur l'utilisation d' using blocs de déclarer des objets qui implémentent IDisposable, ce qui n'est apparemment toujours censé faire. Cependant, je ne vois pas un moyen facile de savoir quand je suis glisse vers le haut. Visual Studio ne semble pas indiquer de quelque manière que ce soit (suis-je raté quelque chose?). Suis-je censé aider à vérifier à chaque fois que je déclarer quoi que ce soit, et de construire progressivement un encyclopédique de la mémoire pour les objets qui sont et qui ne sont pas jetables? Me semble inutile, douloureux, et sujette à erreur.

Comment pensez - vous gérer cela?

EDIT:

En regardant les questions liées à l'encadré, j'ai trouvé une autre question qui précise qu' Dispose() est censé être appelé par le finaliseur de l'objet, de toute façon. Donc, même si vous n'appelez jamais vous-même, il devrait éventuellement se produire, ce qui signifie que vous n'avez pas une fuite de mémoire si vous n'utilisez pas using (qui est ce que je suppose que j'étais vraiment inquiet à propos de tout du long). Le seul inconvénient est que le garbage collector ne sais pas quelle quantité de mémoire est organisé par l'objet non gérées choses, afin de ne pas avoir une idée précise de combien de mémoire sera libérée par la collecte de l'objet. Le résultat sera moins idéal que d'habitude de la performance par le garbage collector.

En bref, c'est pas la fin du monde si je manque une using. Je souhaite juste que quelque chose serait de générer au moins un avertissement pour elle.

(Hors-sujet: pourquoi n'est-il pas spécial markdown pour la liaison à une autre question?)

EDIT:

Ok, très bien, arrêter la recherche. C'est super duper tout tiré dramatique-tamianiveau important d'appeler Dispose() ou nous allons tous mourir.

Maintenant. Étant donné que, pourquoi est-il si facile de l'enfer, pourquoi est-il encore autorisé à faire mal? Vous devez sortir de votre façon de faire les choses. Faire comme tout le reste des résultats dans armageddon (apparemment). Autant pour l'encapsulation, hein?

[Tiges off, dégoûté]

24voto

Marc Gravell Points 482669

FxCop pourrait aider (bien qu'il ne l'avais pas vu un test, j'ai juste mis le feu à elle); mais oui: vous êtes là pour vérifier. IDisposable est tout simplement une partie importante du système que vous devez prendre cette habitude. Utilisation de la fonctionnalité intellisense pour rechercher .D est un bon début (mais pas parfaite).

Cependant, il ne faut pas longtemps pour se familiariser avec les types qui ont besoin de l'élimination; de façon générale, tout ce qui concerne les choses à l'extérieur (connexion, le fichier de base de données), par exemple.

ReSharper fait le travail aussi avec une "mise en construire à l'aide de" option. Il n'offre pas comme une erreur, mais...

Bien sûr, si vous n'êtes pas sûr - essayez using : le compilateur va rire moqueur à vous si vous êtes paranoïaque:

using (int i = 5) {}

Error   1   'int': type used in a using statement must be implicitly convertible to 'System.IDisposable'    

15voto

Scott Dorman Points 25000

Si un objet implémente l' IDisposable interface, c'est pour une raison et vous sont destinés à l'appeler et il ne devrait pas être considéré comme facultatif. La meilleure façon de le faire est d'utiliser un using bloc.

Dispose() n'est pas destiné à être appelé par un finaliseur de l'objet et, en fait, de nombreux objets de mettre en œuvre Dispose() mais pas finaliseur (ce qui est parfaitement valide).

L'idée derrière le modèle dispose est que vous fournissez un peu déterministe pour les non géré les ressources maintenu par l'objet (ou n'importe quel objet dans sa chaîne d'héritage). En ne demandant pas Dispose() correctement, vous absolument pouvez exécuter dans une fuite de mémoire (ou de n'importe quel nombre d'autres problèmes).

L' Dispose() méthode n'est en aucune façon liée à un destructeur. Le plus proche que vous obtenez à un destructeur dans .NET est un outil de finalisation. L'instruction à l'aide ne fait pas de libération de la mémoire...en fait, appelant Dispose() ne fait pas de libération de la mémoire sur le tas managé; il ne dégage des ressources non managées qui lui avait été attribué. La gestion des ressources ne sont pas vraiment libéré jusqu'à ce que le GC s'exécute et recueille l'espace mémoire alloué à l'objet graphique.

Les meilleures façons de déterminer si une classe implémente IDisposable sont:

  • IntelliSense (si il a un Dispose() ou Close() méthode)
  • MSDN
  • Réflecteur
  • Compilateur (si elle n'est pas mise en œuvre d' IDisposable vous obtenez une erreur du compilateur)
  • Le bon sens (si il se sent comme vous devez fermer/libération de l'objet lorsque vous avez terminé, alors vous avez probablement devrait)
  • La sémantique (si il y a un Open(), il y a probablement une correspondante Close() qui doit être appelée)
  • Le compilateur. Essayez de la placer dans un using déclaration. Si ce n'est pas de mettre en œuvre IDisposable, le compilateur génère une erreur.

Penser le modèle dispose que tout au sujet de la portée gestion de durée de vie. Vous souhaitez acquérir les ressources en dernier que possible, le plus rapidement possible, et le libérer dès que possible. L'instruction à l'aide contribue à le faire en veillant à ce qu'un appel à l' Dispose() sera fait, même si il y a des exceptions.

4voto

Motti Points 32921

C'est pourquoi (à mon humble avis) C++RAII est supérieur .NET using déclaration.

Beaucoup de gens ont dit qu' IDisposable est uniquement pour géré par les nations unies des ressources, ceci n'est vrai qu'en fonction de la définition de "ressource". Vous pouvez avoir une Lecture/Écriture de verrouillage de la mise en œuvre de IDisposable , puis de la "ressource" est le conceptuel, l'accès au bloc de code. Vous pouvez avoir un objet qui change le curseur à l'heure de verre dans le constructeur et à l'arrière de la valeur en IDispose , puis de la "ressource" est le changement de curseur. Je dirais que vous utilisez IDisposable quand vous voulez déterministe de l'action à lieu au moment de quitter le champ d'application ne soit la manière dont la portée est à gauche, mais je dois avouer que c'est beaucoup moins accrocheur que de dire "c'est de la gestion géré par les nations unies de la gestion des ressources".

Voir aussi la question sur pourquoi il n'y a pas RAII dans .NET.

4voto

GrahamS Points 3315

En bref, c'est pas la fin du monde si je manque une aide. Je souhaite juste que quelque chose serait de générer au moins un avertissement pour elle.

Le problème ici est que vous ne pouvez pas toujours faire face avec un IDisposable simplement en l'emballant dans un using bloc. Parfois, vous avez besoin de l'objet à accrocher partout pour un peu plus de temps. Dans ce cas, vous devrez appeler son Dispose méthode explicitement vous-même.

Un bon exemple de ceci est l'endroit où une classe utilise une EventWaitHandle (ou un AutoResetEvent) pour communiquer entre les deux fils et vous souhaitez vous Débarrasser de la WaitHandle une fois que le thread est terminé.

Donc il n'est pas aussi simple que certains outil juste vérifier que vous n'créer IDisposable objets au sein d'un using bloc.

3voto

Konrad Rudolph Points 231505

@Atario, non seulement accepté la réponse est fausse, votre propre edit est ainsi. Imaginez la situation suivante (qui a effectivement eu lieu dans un CTP de Visual Studio 2005):

Pour dessiner des graphiques, vous créez des stylos sans se débarrasser d'eux. Les stylos ne nécessitent pas beaucoup de mémoire, mais ils utilisent un GDI+ gérer en interne. Si vous ne jetez pas le stylo, le GDI+ poignée ne sera pas publié. Si votre application n'est pas gourmande en mémoire, un certain temps peut s'écouler sans GC appelé. Cependant, le nombre de GDI+ poignées est restreint et assez bientôt, lorsque vous essayez de créer un nouveau stylo, l'opération échoue.

En fait, dans Visual Studio 2005 CTP, si vous avez utilisé l'application assez longtemps, toutes les polices de soudain passer à "Système".

C'est précisément pourquoi il ne suffit pas de s'appuyer sur la GC pour l'élimination. L'utilisation de la mémoire n'est pas nécessairement corelate avec le nombre de ressources non managées que vous acquérir (et ne relâchez pas). Par conséquent, ces resoures peuvent être épuisés bien avant que le GC est appelé.

En outre, il y a bien sûr l'ensemble des aspects des effets secondaires que ces ressources peuvent avoir (tels que l'accès des verrous qui empêchent d'autres applications de fonctionner correctement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X