.NET Framework Élimination correcte et finalisation des objets


Exemple

Comme Dispose () et les finaliseurs visent des objectifs différents, une classe gérant des ressources externes lourdes de mémoire doit les implémenter. La conséquence est d’écrire la classe pour qu’elle gère bien deux scénarios possibles:

  • Lorsque seul le finaliseur est appelé
  • Lorsque Dispose () est invoqué en premier et plus tard, le finaliseur est également appelé

Une solution consiste à écrire le code de nettoyage de telle sorte que son exécution une ou deux fois produirait le même résultat qu’une exécution unique. La faisabilité dépend de la nature du nettoyage, par exemple:

  • Fermer une connexion à une base de données déjà fermée n'aurait probablement aucun effet, donc cela fonctionne
  • La mise à jour de certains «comptes d'utilisation» est dangereuse et produirait un résultat erroné lorsqu'elle est appelée deux fois au lieu d'une fois.

Une solution plus sûre consiste à s'assurer, par conception, que le code de nettoyage est appelé une seule fois, quel que soit le contexte externe. Cela peut être réalisé de manière classique en utilisant un drapeau dédié:

public class DisposableFinalizable1: IDisposable
{
    private bool disposed = false;

    ~DisposableFinalizable1() { Cleanup(); }

    public void Dispose() { Cleanup(); }

    private void Cleanup()
    {
        if(!disposed)
        {
            // Actual code to release resources gets here, then
            disposed = true;
        }
    }
}

Alternativement, Garbage Collector fournit une méthode spécifique SuppressFinalize () qui permet d'ignorer le finaliseur après l'appel de Dispose:

public class DisposableFinalizable2 : IDisposable
{
    ~DisposableFinalizable2() { Cleanup(); }

    public void Dispose()
    {
        Cleanup();
        GC.SuppressFinalize(this);
    }

    private void Cleanup()
    {
        // Actual code to release resources gets here
    }
}