W Visual Basic implementacja interfejsu IDisposable (wzorzec Dispose) pozwala na poprawne zwalnianie zasobów (np. pliki, połączenia z bazą danych, obiekty graficzne), które nie są zarządzane przez garbage collector.
Typowa implementacja wygląda następująco:
Public Class FileManager Implements IDisposable Private fileStream As FileStream Private disposed As Boolean = False Public Sub New(path As String) fileStream = New FileStream(path, FileMode.Open) End Sub Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub Protected Overridable Sub Dispose(disposing As Boolean) If Not disposed Then If disposing AndAlso fileStream IsNot Nothing Then fileStream.Dispose() End If disposed = True End If End Sub Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub End Class
Ważne: Używaj konstrukcji Using ... End Using — zapewnia to automatyczne wywołanie Dispose:
Using manager As New FileManager("data.txt") ' operacje z plikiem End Using
Szczegóły:
Pytanie: "Po co potrzebne jest wywołanie GC.SuppressFinalize(Me) wewnątrz metody Dispose?"
Poprawna odpowiedź: Informuje garbage collector, że finalizator (Finalizer) nie musi być wywoływany, ponieważ zasoby zostały już ręcznie oczyszczone przez Dispose. Bez tego finalizator zostanie wywołany dodatkowo, co obniży wydajność i może prowadzić do podwójnego oczyszczania.
Historia
W oprogramowaniu bankowym niepoprawnie zaimplementowano IDisposable — zapomniano wywołać Dispose na bazie danych, co doprowadziło do wycieków połączeń. Przeciętnie aplikacja "zawieszała się" po 2–3 dniach ciągłej pracy.
Historia
W serwisie medycznym błędnie implementowano Dispose (brakowało flagi "disposed"). Metoda Dispose była wywoływana wiele razy z rzędu, co prowadziło do prób ponownego zwolnienia tego samego zasobu i wystąpienia wyjątków.
Historia
W edytorze graficznym zapomniano wywołać GC.SuppressFinalize(Me). Finalizator był wykonywany nawet po Dispose, co prowadziło do podwójnego zwolnienia zasobów i niestabilności (naruszenie dostępu).