Jsem požádán o implementaci IDisposable na objekty, které jsou 100% spravovanými prostředky, které neobsahují žádné streamy a žádné velké zdroje.
Chápu důležitost správného nakládání s velkými a nespravovanými prostředky, ale co na druhou stranu rovnice?
Pro objekt, který nemá prospěch z implementace IDisposable (malé plně spravované objekty) , jaký negativní dopad může mít GC.SuppressFinalize, pokud existuje?
Komentáře
Odpovědět
Jediným cílem GC.SuppressFinalize
je:
zabránit finalizátoru uvolnit nespravované zdroje, které již byly uvolněny implementací IDisposable.Dispose.
Jakmile objekt zlikvidujete, měli byste skutečně zavolat GC.SuppressFinalize(this);
, jak je uvedeno v odpovědi na otázku “ Kdy mám použít GC.SuppressFinalize ()? „. Užitečná je také analýza kódu „ CA1816 pravidlo.
Nyní implementujeme IDisposable
na objekty, které nemají nespravované zdroje, vypadají docela divně a pochybně. Protože jediným důvodem, který vám daná osoba dala, bylo: „je to tak, jak jsme to vždy udělali my, uděláte to taky“, místo poskytnutí profilovacích / srovnávacích údajů, které ukazují, že přidání IDisposable
vylepší něco v konkrétním případě, nejsou k tomu skutečné důvody.
Způsobilo by to problémy s výkonem? Těžko říci: záleželo by to na konkrétním případě.
způsobí to další problémy? Samozřejmě. Nepočítáme-li skutečnost, že implementace IDisposable
je bolestivá, pokud je tato praxe příliš používána, kód se stává nečitelným a nelze jej udržovat:
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; } } } } }
Komentáře
- Věřím, že příběh je takový, že už dávno měli nějaké spojení / problémy s únikem proudu, pravděpodobně kvůli netěsnému připojení / příkazu kódu ADO.NET, a to způsobilo obrovské úniky zdrojů. Věděli, že implementace IDisposable na všem by problém vyřešila, a tak to udělali, a fungovalo to. proveďte to na většině objektů.
- @AndrewHoffman: vypadá to jako věrohodné vysvětlení. Stále to ale ' neodůvodňuje současnou praxi.
Odpověď
U třídy IDisposable nemusíte používat vzor těžké váhy („bolestivý“) Dispose + Finalizer, if třída je zapečetěna a třída nemá žádné nespravované prostředky.
V této situaci můžete použít podmnožinu vzoru Dispose + Finalizer, který má pouze public Dispose()
, nemá finalizátor a třída je zapečetěna.
Důvodem pro utěsnění třídy je vyhnout se problémům „Co když má podřízená třída nespravované prostředky?“ a „Co když podřízená třída v budoucnu bude mít nespravované prostředky?“
Joe Duffy, dříve Microsoft, má zdlouhavý (více než 30 stránek) článek, který pojednává o tom, jak správně implementovat IDisposable
a všechny implementace podmnožiny permutace.
Přispěvateli do článku jsou Herb Sutter, Brian Grunkemeyer, Jeff Richter a další lumináři C #. Tento článek je mnohem podrobnější než to, co je uvedeno na MSDN.
Bohužel, nový blogovací modul Joe Duffyho neudělal dobrou práci při zachování původního článku z roku 2005, takže vypadá poněkud zpackaně. Zde je odkaz: http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/
Přeji si, abych mohl připojit svůj dokument MS-Word, který má celý článek Joe Duffyho, mnohem lépe formát. 🙁
IDisposable
v tomto případě zlepšuje paměťovou stopu?IDisposable
bez psaní destruktoru / finalizátoru. Nevím ' nevím, jestli osoba, která vás požádala o implementaciIDisposable
, měla v úmyslu udělat také destruktor. Samozřejmě, pokud třída nemá destruktor, nemá vGC.SuppressFinalize
smysl. Pokud třída má destruktor, nezapomeňte říciGC.SuppressFinalize(this)
, když je metodaDispose
spuštěna. V opačném případě nebude instance snadno shromažďována odpadky, bude zařazena do fronty finalizační fronty a bude shromažďována pouze ve shromažďování generace 2.