2009-04-20 15 views
7

Programowałem w .NET przez cztery lata (głównie w języku C#) i używam IDiposable w znacznym stopniu, ale jeszcze nie znalazłem zapotrzebowania na finalizator. Do czego służą finalizatory?Do czego służą finalizatory?

+5

Btw, jestem Anglikiem i odkryłem, że to naprawdę * naprawdę * * naprawdę dobry pomysł, aby nabrać nawyku pisowni "sfinalizować" i "zainicjować" za pomocą z, a nie s. W przeciwnym razie nigdy nie znajdziesz tych cholernych rzeczy, kiedy szukasz ich w dokumentacji! –

+1

@onebyone - ditto. Podobnie, kolor ... to powodowało irytację, ale teraz uważam je za techniczny termin dla branży i wykonuję zadanie ;-p –

+0

Próbowałem się szkolić - używam go w dokumentacji i publicznej stoi w obliczu kodu, ale po prostu nie mogę zmusić się do zrobienia tego w "prawdziwym życiu". –

Odpowiedz

10

Finalizator to ostatnia próba, aby upewnić się, że coś jest prawidłowo oczyszczone i jest zwykle zarezerwowana dla obiektów, które owijają niezarządzane zasoby, takie jak niezarządzane uchwyty itp., Które nie będą zbierać śmieci.

To jest naprawdę rzadkie, aby napisać finalizator. Na szczęście (iw przeciwieństwie do IDisposable) finalizatory nie muszą być propagowane; więc jeśli masz ClassA z finalizatorem i ClassB, który owija ClassA, to ClassB nie potrzebuje finalizatora - ale całkiem możliwe, że zarówno ClassA, jak i zaimplementują IDisposable.

Dla kodu zarządzanego zwykle wystarcza IDisposable. Nawet jeśli nie posprzątasz poprawnie, ostatecznie zarządzane obiekty zostaną zebrane (zakładając, że zostaną zwolnione).

1

Finalizery służą do czyszczenia zasobów, jeśli nie zostały usunięte.

IE, nic nie wymusza nazywania Dispose(), ale finalizatory są wywoływane automatycznie przez odśmiecnik.

Nie należy polegać na tej funkcjonalności, ponieważ nie ma gwarancji, że (lub jeśli) będzie można pobrać śmieci do obiektu.

2

Finalizery mają na celu uwolnienie zasobów nie kontrolowanych przez garbage collector, takich jak niezarządzany uchwyt. Chociaż może to zrobić Dispose, nie ma gwarancji, że konsument go wywoła.

4

Finalizatory służą tylko do uwolnienia niezarządzanych zasobów, takich jak na przykład bitmapy GDI. Jeśli nie przydzielisz żadnych niezarządzanych zasobów, nie potrzebujesz finalizatorów. Generalnie nie jest dobrym pomysłem dotykanie obiektu managed w finalizatorze, ponieważ kolejność finalizacji nie jest gwarantowana.

Inną przydatną techniką przy użyciu finalizatora jest stwierdzenie, że Dispose został wywołany, gdy wymagana jest aplikacja. To może pomóc złapać kodowania błędy w kompilacji Debug:

void Dispose() 
{ 
    GC.SuppressFinalize(this); 
} 
#if DEBUG 
~MyClass() 
{ 
    Debug.Fail("Dispose was not called."); 
} 
#endif 
1

Wikipedia says:

... O finalizator jest kawałek kodu, który zapewnia, że ​​pewne niezbędne działania są podejmowane, gdy nabyty zasób ... nie jest już używane [bo posiadania obiekt został zebrane śmieci ]

A jeśli nie używasz finalizatora podczas pisania IDisposables, prawdopodobnie masz przecieki pamięci, ponieważ nie ma gwarancji, że właściciel wywoła funkcję Dispose().

MS sami zalecamy napisać coś podobnego do tego w swoje realizatorów:

public void Dispose() 
    { 
     this.Dispose(true); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!this.isDisposed) 
     { 
      if (disposing) 
      { 
       GC.SuppressFinalize(this); 
      } 
     } 
     //Dispose of resources here 
     this.isDisposed = true; 
    } 

    ~DisposableSafe() 
    { 
     this.Dispose(false); 
    } 

    private bool isDisposed = false; 

Osobiście nie znoszę kopiuj-wklej, więc mają tendencję do zawijania, że ​​w abstrakcyjnej klasie do ponownego użycia.

+0

Jeśli twoja klasa nie zajmuje się bezpośrednio zasobami * niezarządzanego *, prawdopodobnie nie potrzebujesz finalizatora. Zarządzane zasoby powinny ostatecznie zostać obsłużone przez GC, niezależnie od tego, czy użytkownik wywołuje Dispose. – LukeH

+0

To jest to, że napisałem "prawdopodobnie" zamiast "prawdopodobnie" i martwiłem się tym. Ale i tak nie jest to prawda. Jeśli twoja klasa implementuje inne IDisposable, to masz obowiązek wywołać Dispose() również na tym. I tak dalej, od MSDN "Głównym zastosowaniem tego interfejsu jest udostępnianie zasobów niezarządzanych". – annakata

Powiązane problemy