Recherche…


Remarques

  • C'est aux clients de la classe implémentant IDisposable de s'assurer qu'ils appellent la méthode Dispose lorsqu'ils ont fini d'utiliser l'objet. Il n'y a rien dans le CLR qui recherche directement les objets pour qu'une méthode Dispose appelle.

  • Il n'est pas nécessaire d'implémenter un finaliseur si votre objet ne contient que des ressources gérées. Assurez-vous d'appeler Dispose sur tous les objets que votre classe utilise lorsque vous implémentez votre propre méthode Dispose .

  • Il est recommandé de sécuriser la classe contre les appels multiples à Dispose , même si elle ne devrait idéalement être appelée qu'une seule fois. Cela peut être réalisé en ajoutant une variable private bool à votre classe et en définissant la valeur sur true lorsque la méthode Dispose est exécutée.

Dans une classe contenant uniquement des ressources gérées

Les ressources gérées sont des ressources connues et contrôlées par le ramasse-miettes de l'environnement d'exécution. Il existe de nombreuses classes disponibles dans la BCL, par exemple, une classe SqlConnection qui est une classe wrapper pour une ressource non gérée. Ces classes implémentent déjà l'interface IDisposable - c'est à votre code de les nettoyer lorsque vous avez terminé.

Il n'est pas nécessaire d'implémenter un finaliseur si votre classe ne contient que des ressources gérées.

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

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

Dans une classe avec des ressources gérées et non gérées

Il est important de laisser la finalisation ignorer les ressources gérées. Le finaliseur s'exécute sur un autre thread - il est possible que les objets gérés n'existent plus au moment où le finaliseur s'exécute. L'implémentation d'une méthode protégée Dispose(bool) est une pratique courante pour s'assurer que les ressources gérées n'ont pas leur méthode Dispose appelée depuis un finaliseur.

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 définit une interface pour les types nécessitant une méthode de suppression:

public interface IDisposable
{
  void Dispose();
}

Dispose() est principalement utilisé pour nettoyer les ressources, comme les références non gérées. Cependant, il peut également être utile de forcer l’élimination des autres ressources même si elles sont gérées. Au lieu d'attendre que le GC finisse par nettoyer votre connexion à la base de données, vous pouvez vous assurer que cela est fait dans votre propre implémentation Dispose() .

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

Lorsque vous devez accéder directement à des ressources non managées, telles que des pointeurs non gérés ou des ressources win32, créez une classe héritant de SafeHandle et utilisez les conventions / outils de cette classe pour le faire.

Dans une classe héritée avec des ressources gérées

Il est assez courant de créer une classe qui implémente IDisposable , puis de dériver des classes contenant également des ressources gérées. Il est recommandé de marquer la méthode Dispose avec le mot clé virtual afin que les clients puissent nettoyer toutes les ressources dont ils sont propriétaires.

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();
    }
}

en utilisant le mot clé

Lorsqu'un objet implémente l' IDisposable interface, il peut être créé dans l' using de la syntaxe:

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");
    }
}

Voir la démo

using sucre syntatique pour un bloc try/finally ; l'utilisation ci-dessus se traduirait à peu près par:

{
    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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow