Kiedy powinienem zaimplementować IDispose w klasie, a nie w destruktorze? Przeczytałem ten artykuł , ale nadal nie rozumiem.
Zakładam, że jeśli zaimplementuję IDispose na obiekcie, mogę wyraźnie go „zniszczyć”, zamiast czekać, aż zrobi to garbage collector. Czy to jest poprawne?
Czy to oznacza, że zawsze powinienem jawnie wywoływać metodę Dispose na obiekcie? Jakie są typowe tego przykłady?
c#
.net
dispose
destructor
Jordan Parmer
źródło
źródło
using
konstrukcji.Odpowiedzi:
Finalizator (aka destructor) jest częścią garbage collector (GC) - jest nieokreślony, kiedy (a nawet jeśli) tak się dzieje, ponieważ GC dzieje się głównie w wyniku presji pamięci (tj. Potrzebuje więcej miejsca). Finalizatory są zwykle używane tylko do czyszczenia niezarządzanych zasobów, ponieważ zasoby zarządzane będą miały własną kolekcję / utylizację.
Stąd
IDisposable
jest używany do deterministycznego czyszczenia obiektów, czyli teraz. Nie gromadzi pamięci obiektu (która nadal należy do GC) - ale służy na przykład do zamykania plików, połączeń z bazami danych itp.Istnieje wiele wcześniejszych tematów na ten temat:
Na koniec należy zauważyć, że nierzadko zdarza się, że
IDisposable
obiekt ma również finalizator; w tym przypadkuDispose()
zwykle wywołujeGC.SuppressFinalize(this)
, co oznacza, że GC nie uruchamia finalizatora - po prostu wyrzuca pamięć (znacznie taniej). Finalizator nadal działa, jeśli zapomnisz oDispose()
obiekcie.źródło
Rolą tej
Finalize()
metody jest zapewnienie, że obiekt .NET może wyczyścić niezarządzane zasoby podczas zbierania elementów bezużytecznych . Jednak obiekty, takie jak połączenia z bazami danych lub programy obsługi plików, powinny zostać zwolnione tak szybko, jak to możliwe, zamiast polegać na usuwaniu elementów bezużytecznych. W tym celu należy zaimplementowaćIDisposable
interfejs i zwolnić zasoby wDispose()
metodzie.źródło
W witrynie MSDN jest bardzo dobry opis :
źródło
Jedyną rzeczą, która powinna znajdować się w destruktorze C #, jest ta linia:
Otóż to. W tej metodzie nie powinno być niczego innego.
źródło
Twoje pytanie, czy zawsze powinieneś dzwonić,
Dispose
jest zwykle gorącą debatą. Zobacz ten blog, aby poznać ciekawą perspektywę szanowanych osób w społeczności .NET.Osobiście uważam, że stanowisko Jeffreya Richtera, że sprawdzanie
Dispose
nie jest obowiązkowe, jest niesamowicie słabe. Podaje dwa przykłady na uzasadnienie swojej opinii.W pierwszym przykładzie mówi, że wywoływanie
Dispose
kontrolek Windows Forms jest żmudne i niepotrzebne w głównych scenariuszach. Jednak nie wspomina, żeDispose
faktycznie jest wywoływana automatycznie przez kontenery kontrolne w tych głównych scenariuszach.W drugim przykładzie stwierdza, że programista może błędnie założyć, że instancja from
IAsyncResult.WaitHandle
powinna zostać agresywnie usunięta, nie zdając sobie sprawy, że właściwość leniwie inicjuje uchwyt oczekiwania, co skutkuje niepotrzebnym spadkiem wydajności. Ale problem z tym przykładem polega na tym, żeIAsyncResult
sam w sobie nie jest zgodny z opublikowanymi przez Microsoft wytycznymi dotyczącymi postępowania zIDisposable
obiektami. Oznacza to, że jeśli klasa zawiera odniesienie doIDisposable
typu, to sama klasa powinna implementowaćIDisposable
. Gdyby postępowanoIAsyncResult
zgodnie z tą zasadą, wówczas jego własnaDispose
metoda mogłaby podjąć decyzję dotyczącą tego, którego z jej członków należy usunąć.Więc jeśli ktoś nie ma bardziej przekonujących argumentów, pozostanę w obozie „zawsze wzywaj utylizację” ze zrozumieniem, że będą pewne przypadki poboczne, które wynikną głównie ze złych wyborów projektowych.
źródło
To naprawdę proste. Wiem, że udzielono odpowiedzi, ale spróbuję ponownie, ale postaram się, aby było to tak proste, jak to tylko możliwe.
Generalnie nigdy nie należy używać destruktora. To tylko run .net chce, żeby działał. Będzie działać tylko po cyklu zbierania śmieci. W rzeczywistości może nigdy nie zostać uruchomiona podczas cyklu życia aplikacji. Z tego powodu nigdy nie należy umieszczać żadnego kodu w destruktorze, który „musi” zostać uruchomiony. Nie można również polegać na tym, że jakiekolwiek istniejące obiekty w klasie będą istniały podczas jej uruchamiania (mogły już zostać wyczyszczone, ponieważ kolejność działania destruktorów nie jest gwarantowana).
IDisposible powinno być używane zawsze, gdy masz obiekt, który tworzy zasoby wymagające oczyszczenia (np. Uchwyty plików i grafiki). W rzeczywistości wielu twierdzi, że wszystko, co umieścisz w destruktorze, powinno być umieszczone w IDisposable z powodów wymienionych powyżej.
Większość klas wywołuje metodę dispose, gdy finalizator jest wykonywany, ale jest to po prostu zabezpieczenie i nigdy nie powinno się na nim polegać. Powinieneś jawnie pozbyć się wszystkiego, co implementuje IDisposable, kiedy skończysz z tym. Jeśli zaimplementujesz IDisposable, powinieneś wywołać dispose w finalizerze. Przykład można znaleźć pod adresem http://msdn.microsoft.com/en-us/library/system.idisposable.aspx .
źródło
Oto kolejny świetny artykuł, który usuwa część mgły otaczającej IDisposable, GC i dispose.
Chris Lyons WebLog Demystifying Dispose
źródło