CA1063 : Implémenter IDisposable correctement

Propriété Value
Identificateur de la règle CA1063
Titre Implémenter IDisposable correctement
Catégorie Conception
Le correctif est cassant ou non cassant Sans rupture
Activé par défaut dans .NET 8 Non

Cause

L’interface System.IDisposable n’est pas implémentée correctement. Les raisons possibles sont les suivantes :

  • IDisposable est réimplémentée dans la classe
  • Finalize est remplacée à nouveau
  • Dispose() est remplacée
  • La méthode Dispose() n’est pas publique, sealed ou nommée Dispose
  • Dispose(bool) n’est pas protégée, virtuelle ou unsealed
  • Dans les types unsealed, Dispose() doit appeler Dispose(true)
  • Pour les types unsealed, l’implémentation Finalize n’appelle ni Dispose(bool) ni le finaliseur de classe de base

La violation de l’un de ces modèles déclenche l’avertissement CA1063.

Chaque type unsealed qui déclare et implémente l’interface IDisposable doit fournir sa propre méthode protected virtual void Dispose(bool). Dispose() doit appeler Dispose(true), et le finaliseur doit appeler Dispose(false). Si vous créez un type unsealed qui déclare et implémente l’interface IDisposable, vous devez définir Dispose(bool) et l’appeler. Pour plus d’informations, consultez Nettoyer des ressources non managées (guide .NET) et Implémenter une méthode Dispose.

Par défaut, cette règle examine uniquement les types visibles en externe, mais elle est configurable.

Description de la règle

Tous les types IDisposable doivent implémenter le modèle Dispose correctement.

Comment corriger les violations

Examinez votre code et déterminez parmi les résolutions suivantes celle qui permettra de résoudre cette violation :

  • Supprimez IDisposable de la liste des interfaces implémentées par votre type, et remplacez l’implémentation Dispose de la classe de base à la place.

  • Supprimez le finaliseur de votre type, remplacez Dispose(bool disposing), et placez la logique de finalisation dans le chemin de code où ’disposing’ est false.

  • Remplacez Dispose(bool disposing) et placez la logique dispose dans le chemin de code où ’disposing’ est true.

  • Veillez à ce que Dispose() soit déclaré comme public et sealed.

  • Renommez votre méthode Dispose et veillez à ce qu’elle soit déclarée comme publique et sealed.

  • Veillez à ce que Dispose(bool) soit déclaré comme protégée, virtuelle et unsealed.

  • Modifiez Dispose() afin qu’elle appelle Dispose(true), puis appelle SuppressFinalize sur l’instance d’objet actuelle (this, ou Me en Visual Basic), puis retourne.

  • Modifiez votre finaliseur afin qu’il appelle Dispose(false), puis retourne.

  • Si vous créez un type unsealed qui déclare et implémente l’interface IDisposable, veillez à ce que l’implémentation de IDisposable suive le modèle décrit plus haut dans cette section.

Quand supprimer les avertissements

Ne supprimez aucun avertissement de cette règle.

Remarque

Vous pouvez voir des avertissements de faux positifs de cette règle si tous les éléments suivants s’appliquent :

  • Vous utilisez Visual Studio 2022 version 17.5 ou ultérieure avec une version antérieure du Kit de développement logiciel (SDK) .NET, c’est-à-dire .NET 6 ou version antérieure.
  • Vous utilisez les analyseurs du Kit de développement logiciel (SDK) .NET 6 ou d’une version antérieure des packages d’analyseurs, comme Microsoft.CodeAnalysis.FxCopAnalyzers.
  • Vous avez des attributs sur votre implémentation IDispose.

Dans ce cas, vous pouvez sans risque supprimer un avertissement faux positif. Les faux positifs sont dus à un changement cassant dans le compilateur C#. Envisagez d’utiliser un analyseur plus récent qui contient le correctif pour les avertissements faux positifs. Effectuez une mise à niveau vers Microsoft.CodeAnalysis.NetAnalyzers version 7.0.0-préversion1.22464.1 ou ultérieure ou utilisez les analyseurs du Kit de développement logiciel (SDK) .NET 7.

Configurer le code à analyser

Utilisez l’option suivante pour configurer les parties de votre codebase sur lesquelles exécuter cette règle.

Vous pouvez configurer cette option pour cette règle uniquement, pour toutes les règles auxquelles elle s’applique ou pour toutes les règles de cette catégorie (Conception) auxquelles elle s’applique. Pour plus d’informations, consultez Options de configuration des règles de qualité du code.

Inclure des surfaces d’API spécifiques

Vous pouvez configurer les parties de votre codebase sur lesquelles exécuter cette règle, en fonction de leur accessibilité. Par exemple, pour spécifier que la règle doit s’exécuter uniquement sur la surface d’API non publique, ajoutez la paire clé-valeur suivante à un fichier .editorconfig dans votre projet :

dotnet_code_quality.CAXXXX.api_surface = private, internal

Exemple de pseudo-code

Le pseudo-code suivant fournit un exemple général de la façon d’implémenter Dispose(bool) dans une classe qui utilise des ressources managées et natives.

public class Resource : IDisposable
{
    private bool isDisposed;
    private IntPtr nativeResource = Marshal.AllocHGlobal(100);
    private AnotherResource managedResource = new AnotherResource();

    // Dispose() calls Dispose(true)
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // The bulk of the clean-up code is implemented in Dispose(bool)
    protected virtual void Dispose(bool disposing)
    {
        if (isDisposed) return;

        if (disposing)
        {
            // free managed resources
            managedResource.Dispose();
        }

        // free native resources if there are any.
        if (nativeResource != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(nativeResource);
            nativeResource = IntPtr.Zero;
        }

        isDisposed = true;
    }

    // NOTE: Leave out the finalizer altogether if this class doesn't
    // own unmanaged resources, but leave the other methods
    // exactly as they are.
    ~Resource()
    {
        // Finalizer calls Dispose(false)
        Dispose(false);
    }
}

Voir aussi