On me demande d’implémenter IDisposable sur des objets qui sont des ressources gérées à 100%, qui ne contiennent aucun flux et aucune ressource volumineuse.
Je comprends limportance de disposer correctement des ressources volumineuses et non gérées, mais quen est-il de lautre côté de léquation?
Pour un objet qui ne bénéficie pas de limplémentation dIDisposable (petits objets entièrement gérés) , quel impact négatif peut avoir GC.SuppressFinalize, le cas échéant?
Commentaires
Réponse
Le seul objectif de GC.SuppressFinalize
est:
dempêcher le finaliseur de libérer des ressources non gérées qui ont déjà été libérées par limplémentation IDisposable.Dispose.
Une fois que vous avez supprimé lobjet, vous devriez en effet appeler GC.SuppressFinalize(this);
, comme indiqué dans une réponse à la question » Quand dois-je utiliser GC.SuppressFinalize ()? « . La règle danalyse de code « CA1816 est également utile.
Maintenant, implémentation de IDisposable
sur les objets qui nont pas de ressources non gérées semblent assez étranges et discutables. Puisque la seule raison que la personne vous a donnée était: « cest juste la façon dont nous » lavons toujours fait, vous le faites aussi « , au lieu de fournir des données de profilage / benchmarking qui montrent que lajout de IDisposable
améliorera quelque chose dans un cas spécifique, il ny a aucune raison réelle de le faire.
Cela poserait-il des problèmes de performances? Difficile à dire: cela dépendrait dun cas particulier.
cela pose dautres problèmes? Bien sûr. Sans compter le fait que IDisposable
est pénible à implémenter, si cette pratique est trop utilisée, le code devient illisible et impossible à maintenir:
public int ComputePrice(Rebate rebate) { using (var currentCurrency = this.User.FindCurrency()) { using (var priceWithoutRebate = this.GetPurePrice()) { using (var canApplyRebate = rebate.CanApplyTo(this)) { if (!canApplyRebate) { return priceWithoutRebate; } using (var priceWithRebate = priceWithoutRebate.Apply(rebate)) { return priceWithRebate; } } } } }
Commentaires
- Eh bien, je crois que lhistoire est quil y a longtemps, ils avaient un lien / des problèmes de fuite de flux, probablement dus à une connexion / commande de code ADO.NET qui fuyait, et cela a provoqué des fuites massives de ressources. Ils savaient que limplémentation dIDisposable sur tout résoudrait le problème, cest ce quils ont fait, et cela a fonctionné. implémentez-le sur la plupart des objets.
- @AndrewHoffman: cela semble être une explication plausible. Mais cela ne justifie toujours pas ' la pratique actuelle.
Réponse
Vous nêtes pas obligé dutiliser le modèle Dispose + Finalizer lourd (« douloureux ») sur une classe IDisposable, if la classe est scellée et la classe na pas de ressources non gérées.
Dans cette situation, vous pouvez utiliser un sous-ensemble du modèle Dispose + Finalizer, qui na que public Dispose()
, na pas de finaliseur et la classe est scellée.
La raison du scellement de la classe est déviter les problèmes de « Et si une classe enfant a des ressources non gérées? » et « Et si une classe enfant à lavenir avait des ressources non gérées? »
Joe Duffy, anciennement de Microsoft, a un long article (plus de 30 pages) qui explique comment implémenter correctement IDisposable
, et toutes les implémentations du sous-ensemble de permutation.
Les contributeurs à larticle incluent Herb Sutter, Brian Grunkemeyer, Jeff Richter et dautres personnalités du C #. Larticle est beaucoup plus détaillé que ce qui est présenté sur MSDN.
Hélas, le nouveau moteur de blog de Joe Duffy n’a pas réussi à conserver l’article original de 2005, il semble donc quelque peu bouché. Voici le lien: http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/
Jaimerais pouvoir joindre mon document MS-Word qui contient lintégralité de larticle de Joe Duffy dans un bien meilleur format. 🙁
IDisposable
dans ce cas améliore lempreinte mémoire?IDisposable
sans écrire de destructeur / finaliseur. Je ne ' ne sais pas si la personne qui vous a demandé dimplémenterIDisposable
voulait dire que vous deviez également créer un destructeur. Bien sûr, si la classe na pas de destructeur, il ny a aucun point dansGC.SuppressFinalize
. Si la classe a un destructeur, assurez-vous de direGC.SuppressFinalize(this)
lorsque votre méthodeDispose
est exécutée. Sinon, linstance ne sera pas récupérée facilement, elle sera mise en file dattente sur une file dattente de finaliseur et ne sera collectée que dans une collecte de génération 2.