Mij wordt gevraagd IDisposable te implementeren op objecten die 100% beheerde bronnen zijn, die geen streams en geen grote bronnen bevatten.
Ik begrijp het belang van het op de juiste manier verwijderen van grote bronnen en onbeheerde bronnen, maar hoe zit het met de andere kant van de vergelijking?
Voor een object dat geen baat heeft bij het implementeren van IDisposable (kleine volledig beheerde objecten) , welke negatieve impact kan GC.SuppressFinalize hebben, indien van toepassing?
Reacties
Antwoord
Het enige doel van GC.SuppressFinalize
is:
voorkomen dat de finalizer onbeheerde bronnen vrijgeeft die zijn al bevrijd door de IDisposable.Dispose-implementatie.
Zodra je het object hebt verwijderd, zou je inderdaad GC.SuppressFinalize(this);
moeten aanroepen, zoals getoond in een antwoord op de vraag ” Wanneer moet ik GC.SuppressFinalize () gebruiken? “. Code-analyse “ CA1816 -regel is ook nuttig.
Implementeer nu IDisposable
op objecten die geen onbeheerde bronnen hebben, zien er vreemd en twijfelachtig uit. Omdat de enige reden die de persoon je gaf was: “het is gewoon zoals we” het altijd hebben gedaan, jij doet het ook “, in plaats van profilering / benchmarkinggegevens te verstrekken waaruit blijkt dat het toevoegen van IDisposable
zal iets verbeteren in een specifiek geval, er zijn geen echte redenen om het te doen.
Zou het prestatieproblemen veroorzaken? Moeilijk te zeggen: het hangt af van het specifieke geval.
Zou veroorzaakt het andere problemen? Natuurlijk. Nog afgezien van het feit dat IDisposable
pijnlijk is om te implementeren, wordt de code onleesbaar en onmogelijk te onderhouden als deze praktijk te vaak wordt gebruikt:
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; } } } } }
Reacties
- Nou, ik geloof dat het verhaal is dat ze lang geleden enige connectie hadden / problemen met lekken van streams, waarschijnlijk als gevolg van een lekkende verbinding / commando ADO.NET-code, en dit veroorzaakte enorme lekken van bronnen. Ze wisten dat het probleem zou worden opgelost door IDisposable op alles te implementeren, dus dat deden ze, en het werkte. En dus nu j Implementeer het op de meeste objecten.
- @AndrewHoffman: het lijkt een plausibele verklaring. Maar het rechtvaardigt nog steeds geen ' de huidige praktijk.
Antwoord
U hoeft het zware (“pijnlijke”) Dispose + Finalizer-patroon niet te gebruiken voor een IDisposable-klasse, if de klasse is verzegeld en de klasse heeft geen onbeheerde bronnen.
In die situatie kunt u een subset van het Dispose + Finalizer-patroon gebruiken, die alleen public Dispose()
, heeft geen finalizer en de klas is verzegeld.
De reden voor het verzegelen van de klas is om de problemen te vermijden van “Wat als een kinderklasse onbeheerde bronnen heeft?” en “Wat als een onderliggende klas in de toekomst onbeheerde bronnen zal hebben?”
Joe Duffy, voorheen van Microsoft, heeft een uitgebreid artikel (meer dan 30 paginas) waarin wordt besproken hoe , en alle permutatiesubsetimplementaties.
Bijdragers aan het artikel zijn onder andere Herb Sutter, Brian Grunkemeyer, Jeff Richter en andere C # -armaturen. Het artikel is veel dieper dan wat wordt gepresenteerd op MSDN.
Helaas, de nieuwe blog-engine van Joe Duffy heeft het oorspronkelijke artikel uit 2005 niet goed bewaard, dus het ziet er wat misvormd uit. Hier is de link: http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/
Ik wou dat ik mijn MS-Word-document kon bijvoegen dat het volledige artikel van Joe Duffy bevat in een veel betere formaat. 🙁
IDisposable
in dit geval de geheugenvoetafdruk verbetert?IDisposable
te implementeren zonder een destructor / finalizer te schrijven. Ik weet niet ' of de persoon die je vroeg omIDisposable
te implementeren, bedoelde dat je ook een vernietiger moest maken. Als de klasse geen destructor heeft, heeft het natuurlijk geen zinGC.SuppressFinalize
. Als de klasse een destructor heeft, vergeet dan nietGC.SuppressFinalize(this)
te zeggen wanneer uwDispose
-methode is uitgevoerd. Anders wordt de instantie niet gemakkelijk garbage-verzameld, het wordt in de wachtrij van een finalizer geplaatst en alleen verzameld in een generatie-2-verzameling.