Jeg bliver bedt om at implementere IDisposable på objekter, der er 100% administrerede ressourcer, der ikke indeholder nogen streams og ingen store ressourcer.
Jeg forstår vigtigheden af korrekt bortskaffelse af store ressourcer og ikke-administrerede ressourcer, men hvad med den anden side af ligningen?
For et objekt, der ikke har gavn af at implementere IDisposable (små fuldt administrerede objekter) , hvilken negativ indvirkning kan GC.SuppressFinalize have, hvis nogen?
Kommentarer
Svar
Det eneste mål for GC.SuppressFinalize
er:
for at forhindre, at finalisatoren frigiver uhåndterede ressourcer, der er allerede blevet frigivet af IDisposable.Dispose implementering.
Når du har bortskaffet objektet, skal du faktisk kalde GC.SuppressFinalize(this);
, som vist i et svar på spørgsmålet ” Hvornår skal jeg bruge GC.SuppressFinalize ()? “. Kodeanalyse “ CA1816 -reglen er også nyttig.
Nu implementeres IDisposable
på objekter, der ikke har ikke-administrerede ressourcer, ser ret underlige og tvivlsomme ud. Da den eneste grund til, at personen gav dig, var: “det er bare den måde, vi” altid har gjort det, gør du det også “i stedet for at levere profilerings- / benchmarkingdata, der viser, at tilføjelse af IDisposable
vil forbedre noget i en bestemt sag, der er ingen faktiske grunde til at gøre det.
Ville det medføre ydeevneproblemer? Vanskeligt at sige: det ville afhænge af en bestemt sag.
Ville Det medfører andre problemer? Selvfølgelig. Tæller ikke det faktum, at IDisposable
er smertefuldt at implementere, hvis denne praksis bruges for meget, bliver koden uleselig og umulig at vedligeholde:
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
- Nå, jeg tror historien er, at de for længe siden havde en vis forbindelse / stream lækage problemer, sandsynligvis på grund af utæt forbindelse / kommando ADO.NET kode, og dette forårsagede massive ressource lækager. De vidste, at implementering af IDisposable på alt ville løse problemet, så de gjorde det, og det fungerede. Og så nu j de bare implementer det på de fleste objekter.
- @AndrewHoffman: det virker som en plausibel forklaring. Men det berettiger stadig ikke ' t den nuværende praksis.
Svar
Du behøver ikke bruge det tunge (“smertefulde”) bortskaffelses- + finaliseringsmønster på en ID-disponibel klasse, hvis klassen er forseglet, og klassen har ingen ikke-administrerede ressourcer.
I den situation kan du bruge en delmængde af Dispose + Finalizer-mønsteret, som bare har offentlig Dispose()
, har ingen finalizer, og klassen er forseglet.
Årsagen til at forsegle klassen er at undgå problemerne med “Hvad hvis en barneklasse har ikke-administrerede ressourcer?” og “Hvad hvis en underordnet klasse i fremtiden vil have ikke-administrerede ressourcer?”
Joe Duffy, tidligere Microsoft, har en lang artikel (30+ sider), der diskuterer, hvordan man korrekt implementerer IDisposable
og alle permutationsimplementeringsimplementeringer.
Bidragydere til artiklen inkluderer Herb Sutter, Brian Grunkemeyer, Jeff Richter og andre C # -armaturer. Artiklen er meget mere dybtgående end hvad der præsenteres på MSDN.
Ak, Joe Duffys nye blogmotor har ikke gjort et godt stykke arbejde med at bevare den originale artikel fra 2005, så den ser noget munged ud. Her er linket: http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/
Jeg ville ønske, at jeg kunne vedhæfte mit MS-Word-dokument, der har hele Joe Duffys artikel i en meget bedre format. 🙁
IDisposable
i dette tilfælde forbedrer hukommelsesfodaftryk?IDisposable
uden at skrive en destruktor / finalizer. Jeg ved ikke ' om den person, der bad dig om at implementereIDisposable
, mente at du også skulle gøre en destruktør. Selvfølgelig, hvis klassen ikke har nogen destruktor, er der ingen mening iGC.SuppressFinalize
. Hvis klassen har en destruktor, skal du sørge for at sigeGC.SuppressFinalize(this)
når dinDispose
-metode er kørt. Ellers bliver forekomsten ikke let indsamlet skrald, den vil stå i kø i en finalizer-kø og kun indsamles i en generation-2-indsamling.