Interfejs IDisposable w języku C#

IDisposable - zwalnianie niezarządzanych zasobów


Głównym zastosowaniem interfejsu IDisposable jest zwalnianie niezarządzanych zasobów. Niezarządzane zasoby są to elementy takie jak np. pliki, strumienie i uchwyty do okien przechowywane przez obiekt. Aby zwolnić zasoby wywołujemy metodę Dispose(). W przypadku użycia Entity Frameworka (EF) zalecane jest używanie metody Dispose() dla contextu, zależy nam, aby zasoby były używane jak najkrótszy czas. Każde połączenie z bazą danych po zakończonym odczycie staje się bezużyteczne, ponieważ przy kolejny zapytaniu jest tworzone osobne połączenie z bazą, dlatego metoda Dispose pozwala na kontrolowane zwolnienie zasobów po prawidłowym odczycie danych. Podobnie wygląda sytuacja w przypadku odczytu plików czy połączenia z Internetem.
W przypadku użycia destruktora i Garbage Collectora nie mamy wpływu na długość istnienia obiektu, ponieważ obiekty są trzymane jak najdłużej w celu ich ponownego użycia i są kasowane dopiero w momencie braku zasobów. Przyjęta została zasada, że każda klasa która działa na zewnętrznych zasobach oraz musi te zasoby zwalniać powinna dziedziczyć po interfejsie IDisposable. W przypadku korzystania z kontenera Inversion of Control (IoC zostanie dokładniej opisane w późniejszej części pracy w rozdziale wzorce projektowe) nie ma potrzeby korzystania z metody Dispose(), ponieważ dla każdego typu obiektu deklarujemy jego cykl życia. Przykładowo dla połączenia z bazą danych jest to PerWebRequest, czyli za każdym razem jest tworzony nowy obiekt a kontener IoC automatycznie wywoła metodę Dispose() po zakończonym odczycie danych.

Przykładowy kod prawidłowego użycia Dispose():

public class MojaKlasa:IDisposable
{
    private bool IsDisposed=false;
    public void Dispose()
    {
        Dispose(true);
        GC.SupressFinalize(this);
    }
    protected void Dispose(bool Diposing)
    {
        if(!IsDisposed) {
            if(Disposing)
            { // zwalniaj zasoby zarządzalne }
            // zwalniaj zasoby niezarządzalne
        }
        IsDisposed=true;
    }
    ~MojaKlasa()
    {
        Dispose(false);
    }
}
Taka implementacja metody Dispose() gwarantuje nam, że zasoby niezarządzalne zostaną wyczyszczone bez względu na to czy obiekt będzie automatycznie czyszczony przez Garbage Collectora czy poprzez metodę Dispose() wywołaną przez użytkownika. Dzieje się tak dzięki implementacji destruktora. Gdy użytkownik chce zwolnić obiekt informujemy Garbage Collector że przejmujemy odpowiedzialność za obiekt przy pomocy metody SupressFinalize(). Dzięki temu destruktor nie zostaje wywołany a my używamy metody Dispose() z parametrem bool, który zabezpiecza przed podwójnym wykonaniem tej samej operacji. W przypadku gdy Garbage Collector będzie chciał zwolnić zasoby jako pierwszy, zostaje wywołany destruktor wywołujący metodę Dispose() na zasobach niezarządzalnych.

Więcej informacji na temat interfejsu IDisposable:

http://msdn.microsoft.com/pl-pl/library/system.idisposable.aspx
Komentarze facebook (polub nasz profil na FB aby je zobaczyć):