Jeg blir bedt om å implementere IDisposable på objekter som er 100% administrerte ressurser, som ikke inneholder strømmer og ingen store ressurser.
Jeg forstår viktigheten av å disponere store ressurser og ikke-administrerte ressurser på riktig måte, men hva med den andre siden av ligningen?
For et objekt som ikke har nytte av å implementere IDisposable (små fullt administrerte objekter) , hvilken negativ innvirkning kan GC.SuppressFinalize ha, hvis noen?
Kommentarer
Svar
Det eneste målet med GC.SuppressFinalize
er:
for å forhindre at sluttbehandleren frigjør uhåndterte ressurser som har allerede blitt frigjort av IDisposable.Dispose implementering.
Når du har disponert objektet, bør du faktisk kalle GC.SuppressFinalize(this);
, som vist i et svar på spørsmålet » Når skal jeg bruke GC.SuppressFinalize ()? «. Kodeanalyse « CA1816 -regelen er også nyttig.
Nå implementerer du IDisposable
på gjenstander som ikke har ubehandlede ressurser, ser ganske rare og tvilsomme ut. Siden den eneste grunnen til at personen ga deg var: «det er akkurat slik vi alltid har gjort det, du gjør det også», i stedet for å gi profilerings- / benchmarkingdata som viser at å legge til IDisposable
vil forbedre noe i et bestemt tilfelle, det er ingen faktiske grunner til å gjøre det.
Ville det forårsake ytelsesproblemer? Vanskelig å si: det vil avhenge av en bestemt sak.
Ville det forårsaker andre problemer? Selvfølgelig. Teller ikke det faktum at IDisposable
er smertefullt å implementere, hvis denne fremgangsmåten brukes for mye, blir koden uleselig og umulig å opprettholde:
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; } } } } }
Kommentarer
- Vel, jeg tror historien er at for lenge siden hadde de en viss forbindelse / strømlekkingsproblemer, sannsynligvis på grunn av utett tilkobling / kommando ADO.NET-kode, og dette forårsaket enorme ressurlekkasjer. De visste at implementering av IDisposable på alt ville løse problemet, så de gjorde det, og det fungerte. Og så nå j bare implementer det på de fleste objekter.
- @AndrewHoffman: det virker som en sannsynlig forklaring. Men det rettferdiggjør fortsatt ikke ' t dagens praksis.
Svar
Du trenger ikke å bruke det tunge («smertefulle») avhending + finaliseringsmønsteret på en ID-disponibel klasse, hvis klassen er forseglet, og klassen har ingen uadministrerte ressurser.
I den situasjonen kan du bruke en delmengde av Dispose + Finalizer-mønsteret, som bare har offentlig Dispose()
, har ingen sluttbehandler, og klassen er forseglet.
Årsaken til å forsegle klassen er å unngå problemene med «Hva om en barneklasse har uadministrerte ressurser?» og «Hva om en barneklasse i fremtiden vil ha uadministrerte ressurser?»
Joe Duffy, tidligere Microsoft, har en lang (30+ sider) artikkel som diskuterer hvordan du korrekt implementerer IDisposable
, og alle permutasjonsundersettingsimplementeringene.
Bidragsytere til artikkelen inkluderer Herb Sutter, Brian Grunkemeyer, Jeff Richter og andre C # -armaturer. Artikkelen er mye mer inngående enn det som presenteres på MSDN.
Akk, Joe Duffys nye bloggmotor har ikke gjort en god jobb med å bevare den opprinnelige artikkelen fra 2005, så den ser noe stukket ut. Her er lenken: http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/
Jeg skulle ønske jeg kunne legge ved MS-Word-dokumentet mitt som har hele Joe Duffys artikkel i en mye bedre format. 🙁
IDisposable
i dette tilfellet forbedrer minnefotavtrykket?IDisposable
uten å skrive en destruktor / finalizer. Jeg vet ikke ' om personen som ba deg implementereIDisposable
mente at du også skulle lage en destruktør. Selvfølgelig, hvis klassen ikke har noen ødelegger, er det ingen vits iGC.SuppressFinalize
. Hvis klassen har en destruktør, må du siGC.SuppressFinalize(this)
nårDispose
-metoden din har kjørt. Ellers vil ikke forekomsten lett bli samlet inn søppel, den vil stå i kø i en finalizer-kø og bare bli samlet i en generasjon-2-samling.