Szukaj…


Uwagi

  • Klienci klasy implementujący IDisposable muszą upewnić się, że wywołują metodę Dispose po zakończeniu używania obiektu. W CLR nie ma niczego, co bezpośrednio przeszukuje obiekty w celu wywołania metody Dispose .

  • Implementacja finalizatora nie jest konieczna, jeśli obiekt zawiera tylko zasoby zarządzane. Pamiętaj, aby wywołać Dispose na wszystkich obiektach używanych przez twoją klasę podczas implementacji własnej metody Dispose .

  • Zaleca się, aby uczynić klasę bezpieczną przed wieloma wywołaniami Dispose , chociaż najlepiej byłoby wywołać ją tylko raz. Można to osiągnąć przez dodanie private bool zmiennej private bool do swojej klasy i ustawienie wartości true po uruchomieniu metody Dispose .

W klasie zawierającej tylko zarządzane zasoby

Zarządzane zasoby to zasoby, o których kolektor śmieci środowiska wykonawczego jest świadomy i pod kontrolą. W BCL dostępnych jest wiele klas, na przykład SqlConnection która jest klasą opakowania dla niezarządzanego zasobu. Klasy te już implementują interfejs IDisposable - to zależy od twojego kodu, aby je wyczyścić po zakończeniu.

Implementacja finalizatora nie jest konieczna, jeśli klasa zawiera tylko zasoby zarządzane.

public class ObjectWithManagedResourcesOnly : IDisposable
{
    private SqlConnection sqlConnection = new SqlConnection();

    public void Dispose()
    {
        sqlConnection.Dispose();
    }
}

W klasie z zarządzanymi i niezarządzanymi zasobami

Ważne jest, aby finalizacja ignorowała zarządzane zasoby. Finalizator działa na innym wątku - możliwe jest, że zarządzane obiekty już nie istnieją do czasu uruchomienia finalizatora. Wdrażanie chronionej metody Dispose(bool) jest powszechną praktyką zapewniającą, że zasoby zarządzane nie mają wywoływanej metody Dispose z finalizatora.

public class ManagedAndUnmanagedObject : IDisposable
{
    private SqlConnection sqlConnection = new SqlConnection();
    private UnmanagedHandle unmanagedHandle = Win32.SomeUnmanagedResource();
    private bool disposed;

    public void Dispose()
    {
        Dispose(true); // client called dispose
        GC.SuppressFinalize(this); // tell the GC to not execute the Finalizer
    }

    protected virtual void Dispose(bool disposeManaged)
    {
        if (!disposed)
        {
            if (disposeManaged)
            {
                if (sqlConnection != null)
                {
                    sqlConnection.Dispose();
                }
            }

            unmanagedHandle.Release();

            disposed = true;
        }
    }

    ~ManagedAndUnmanagedObject()
    {
        Dispose(false);
    }
}

IDisposable, Dispose

.NET Framework definiuje interfejs dla typów wymagających metody usuwania:

public interface IDisposable
{
  void Dispose();
}

Dispose() służy przede wszystkim do czyszczenia zasobów, takich jak niezarządzane odwołania. Jednak może być również przydatne wymuszenie dysponowania innymi zasobami, nawet jeśli są one zarządzane. Zamiast czekać, aż GC ostatecznie wyczyści również połączenie z bazą danych, możesz upewnić się, że zostało to zrobione we własnej implementacji Dispose() .

public void Dispose()
{
   if (null != this.CurrentDatabaseConnection)
   {
       this.CurrentDatabaseConnection.Dispose();
       this.CurrentDatabaseConnection = null;
   }
}

Gdy potrzebujesz bezpośredniego dostępu do niezarządzanych zasobów, takich jak niezarządzane wskaźniki lub zasoby win32, utwórz klasę dziedziczącą po SafeHandle i użyj do tego konwencji / narzędzi tej klasy.

W odziedziczonej klasie z zarządzanymi zasobami

Dość często zdarza się, że możesz stworzyć klasę, która implementuje IDisposable , a następnie wyprowadzić klasy, które również zawierają zasoby zarządzane. Zaleca się oznaczenie metody Dispose virtual słowem kluczowym, aby klienci mieli możliwość wyczyszczenia wszelkich posiadanych zasobów.

public class Parent : IDisposable
{
    private ManagedResource parentManagedResource = new ManagedResource();

    public virtual void Dispose()
    {
        if (parentManagedResource != null)
        {
            parentManagedResource.Dispose();
        }
    }
}

public class Child : Parent
{
    private ManagedResource childManagedResource = new ManagedResource();

    public override void Dispose()
    {
        if (childManagedResource != null)
        {
            childManagedResource.Dispose();
        }
        //clean up the parent's resources
        base.Dispose();
    }
}

za pomocą słowa kluczowego

Gdy obiekt implementuje interfejs IDisposable , można go utworzyć w składni using :

using (var foo = new Foo())
{
    // do foo stuff
} // when it reaches here foo.Dispose() will get called

public class Foo : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("dispose called");
    }
}

Zobacz demo

using jest cukrem syntatycznym do blokowania try/finally ; powyższe użycie z grubsza przełoży się na:

{
    var foo = new Foo();
    try
    {
        // do foo stuff
    }
    finally
    {
        if (foo != null)
            ((IDisposable)foo).Dispose();
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow