Poproszono mnie o zaimplementowanie IDisposable na obiektach, które są w 100% zarządzanymi zasobami, które nie zawierają strumieni ani dużych zasobów.

Rozumiem, jak ważne jest prawidłowe pozbywanie się dużych zasobów i niezarządzanych zasobów, ale co z drugą stroną równania?

W przypadku obiektu, który nie korzysta z implementacji IDisposable (małe, w pełni zarządzane obiekty) Jaki negatywny wpływ może mieć GC.SuppressFinalize, jeśli w ogóle?

Komentarze

  • Wygląda na przedwczesną optymalizację. Czy możesz zapytać osobę, która Cię o to poprosiła, o wyniki, jakie uzyskał z profilowania i testów porównawczych, które pokazują, że dodanie w tym przypadku poprawia zużycie pamięci?
  • @MainMa Nie, ale to nie ' nie powstrzymało mnie od zadawania pytań. W rezultacie otrzymaliśmy 5-minutową odpowiedź " tak, jak zawsze ' robiliśmy to, Ty też to robisz ".
  • Cóż, możliwe jest zaimplementowanie IDisposable bez pisania destruktora / finalizatora. Nie ' nie wiem, czy osoba, która poprosiła cię o zaimplementowanie , miała na myśli, że powinieneś również stworzyć destruktor. Oczywiście, jeśli klasa nie ma destruktora, GC.SuppressFinalize nie ma sensu. Jeśli klasa ma destruktor, pamiętaj, aby powiedzieć GC.SuppressFinalize(this) po uruchomieniu metody Dispose. W przeciwnym razie instancja nie zostanie łatwo zebrana jako śmieci, zostanie umieszczona w kolejce finalizatora i zostanie zebrana tylko w kolekcji 2. generacji.
  • @JeppeStigNielsen Pytanie stwierdza, że obiekty mają do czynienia z całkowicie zarządzanymi zasobów, więc ' nie ma potrzeby posiadania finalizatora. Jeśli ktoś tam jest, wiemy, że ' jest zły.

Odpowiedź

Jedynym celem GC.SuppressFinalize jest:

uniemożliwienie finalizatorowi zwolnienia niezarządzanych zasobów, które zostały już zwolnione przez implementację IDisposable.Dispose.

Źródło: MSDN

Po usunięciu obiektu powinieneś rzeczywiście zadzwonić do GC.SuppressFinalize(this);, jak pokazano w , odpowiedzią na pytanie ” Kiedy należy używać GC.SuppressFinalize ()? ”. Przydatna jest również reguła analizy kodu „ CA1816 .

Teraz zaimplementowano IDisposable na obiekty, które nie mają niezarządzanych zasobów, wyglądają dość dziwnie i wątpliwie. Ponieważ jedyny powód, dla którego ta osoba Ci podała, brzmiał: „tak po prostu robiliśmy zawsze, Ty też to robisz”, zamiast podawać dane dotyczące profilowania / analizy porównawczej, które pokazują, że dodanie poprawi coś w konkretnym przypadku, nie ma faktycznych powodów, aby to zrobić.

Czy spowodowałoby to problemy z wydajnością? Trudno powiedzieć: zależałoby to od konkretnego przypadku.

Czy powoduje jakieś inne problemy? Oczywiście. Nie licząc faktu, że implementacja jest bolesna, jeśli ta praktyka jest używana zbyt często, kod staje się nieczytelny i niemożliwy do utrzymania:

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; } } } } } 

Komentarze

  • Cóż, wydaje mi się, że historia jest taka, że dawno temu mieli jakiś związek / problemy z wyciekiem strumienia, prawdopodobnie z powodu nieszczelnego połączenia / komendy w kodzie ADO.NET, co spowodowało ogromne wycieki zasobów. Wiedzieli, że wdrożenie IDisposable na wszystkim rozwiąże problem, więc zrobili i zadziałało. I teraz j Po prostu zaimplementuj to na większości obiektów.
  • @AndrewHoffman: wydaje się to wiarygodnym wyjaśnieniem. Ale nadal nie ' nie uzasadnia obecnej praktyki.

Odpowiedź

Nie musisz używać ciężkiego („bolesnego”) wzorca Dispose + Finalizer w klasie IDisposable, if klasa jest zapieczętowana, a klasa nie ma niezarządzanych zasobów.

W takiej sytuacji można użyć podzbioru wzorca Dispose + Finalizer, który ma tylko public Dispose(), nie ma finalizatora, a klasa jest zapieczętowana.

Powodem zapieczętowania klasy jest uniknięcie problemu „Co jeśli klasa podrzędna ma niezarządzane zasoby?” oraz „A co, jeśli klasa podrzędna w przyszłości będzie miała niezarządzane zasoby?”

Joe Duffy, dawniej pracownik firmy Microsoft, opublikował obszerny (ponad 30 stron) artykuł omawiający, jak poprawnie zaimplementować IDisposable i wszystkie implementacje podzbiorów permutacji.

Współautorami artykułu są: Herb Sutter, Brian Grunkemeyer, Jeff Richter i inni luminarze C #. Artykuł jest znacznie bardziej szczegółowy niż to, co jest prezentowane w witrynie MSDN.

Niestety, nowy silnik blogów Joe Duffyego nie spisał się dobrze, jeśli chodzi o zachowanie oryginalnego artykułu z 2005 roku, więc wygląda na to, że coś się zepsuło. Oto link: http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/

Chciałbym móc załączyć mój dokument MS-Word, który zawiera całość artykułu Joe Duffyego w znacznie lepszej format. 🙁

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *