Mi se cere să implementez ID-ul care poate fi pus pe resurse 100% gestionate, care nu conțin fluxuri și nu au resurse mari.
Înțeleg importanța eliminării corespunzătoare a resurselor mari și a resurselor neadministrate, dar ce se întâmplă cu cealaltă parte a ecuației?
Pentru un obiect care nu beneficiază de implementarea IDisposable (obiecte mici complet gestionate) , ce impact negativ poate avea GC.SuppressFinalize, dacă există?
Comentarii
Răspuns
Singurul obiectiv al GC.SuppressFinalize
este:
pentru a împiedica finalizatorul să elibereze resurse neadministrate care au fost deja eliberați de IDisposable.Dispose implementarea.
Odată ce ați eliminat obiectul, ar trebui să apelați într-adevăr GC.SuppressFinalize(this);
, așa cum se arată în un răspuns la întrebarea ” Când ar trebui să folosesc GC.SuppressFinalize ()? „. Analiza codului „ regula CA1816 este de asemenea utilă.
Acum, implementarea IDisposable
pe obiectele care nu au resurse necontrolate par destul de ciudate și discutabile. Deoarece singurul motiv pe care ți l-a dat persoana a fost: „așa cum am făcut-o întotdeauna, o faci și tu”, în loc să oferi date de profilare / comparare care arată că adăugarea IDisposable
va îmbunătăți ceva într-un caz specific, nu există motive reale pentru a face acest lucru.
Ar provoca probleme de performanță? Greu de spus: ar depinde de un anumit caz.
cauzează alte probleme? Desigur. Fără a lua în considerare faptul că IDisposable
este dureros de implementat, dacă această practică este folosită prea mult, codul devine ilizibil și imposibil de întreținut:
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; } } } } }
Comentarii
- Ei bine, cred că povestea este că, cu mult timp în urmă, aveau o oarecare legătură / probleme legate de scurgeri de flux, probabil din cauza conexiunii scurte / a codului ADO.NET de comandă, iar acest lucru a provocat scurgeri masive de resurse. Știau că implementarea IDisposable pe tot va rezolva problema, așa că au făcut-o și a funcționat. trebuie să îl implementați pe majoritatea obiectelor.
- @AndrewHoffman: pare o explicație plauzibilă. Dar încă nu ' nu justifică practica curentă.
Răspuns
Nu trebuie să utilizați modelul Dispose + Finalizer pentru greutate mare („dureros”) pe o clasă IDisposable, dacă clasa este sigilată, iar clasa nu are resurse neadministrate.
În această situație, puteți utiliza un subset al modelului Dispose + Finalizer, care are doar Dispose()
, nu are finalizator, iar clasa este sigilată.
Motivul sigilării clasei este de a evita problemele „Ce se întâmplă dacă o clasă copil are resurse neadministrate?” și „Ce se întâmplă dacă o clasă de copii în viitor va avea resurse neadministrate?”
Joe Duffy, fost Microsoft, are un articol lung (peste 30 de pagini) care discută despre cum să implementați corect IDisposable
și toate implementările de subset de permutare.
Contribuitorii la articol includ Herb Sutter, Brian Grunkemeyer, Jeff Richter și alți corpuri de iluminat C #. Articolul este mult mai aprofundat decât ceea ce este prezentat pe MSDN.
Din păcate, noul motor de blog al lui Joe Duffy nu a făcut o treabă bună de conservare a articolului original din 2005, așa că pare oarecum înțeles. / div> http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/
Mi-aș dori să pot atașa documentul MS-Word care conține întregul articol al lui Joe Duffy într-un text mult mai bun format. 🙁
IDisposable
în acest caz îmbunătățește amprenta memoriei?IDisposable
fără a scrie un destructor / finalizator. Nu ' nu știu dacă persoana care v-a cerut să implementațiIDisposable
a însemnat că ar trebui să faceți și un distructor. Desigur, dacă clasa nu are destructor, nu are niciun punct înGC.SuppressFinalize
. Dacă clasa are un destructor, asigurați-vă că spunețiGC.SuppressFinalize(this)
când metoda dvs.Dispose
a rulat. În caz contrar, instanța nu va fi colectată cu ușurință, va fi pusă în coadă pe o coadă de finalizare și va fi colectată doar într-o colecție de generația 2.