Condividi tramite


CA1063: Implementare IDisposable correttamente

Proprietà valore
ID regola CA1063
Title Implementare IDisposable correttamente
Categoria Progettazione
La correzione causa un'interruzione o meno Non causa un'interruzione
Abilitato per impostazione predefinita in .NET 9 No

Causa

L'interfaccia System.IDisposable non è implementata correttamente. I possibili motivi per questo includono:

  • IDisposable viene riimplementato nella classe .
  • Finalize viene nuovamente sottoposto a override.
  • Dispose() viene sottoposto a override.
  • Il Dispose() metodo non è pubblico, sealed o denominato Dispose.
  • Dispose(bool) non è protetto, virtuale o non bloccato.
  • Nei tipi non bloccati, Dispose() deve chiamare Dispose(true).
  • Per i tipi non bloccati, l'implementazione Finalize non chiama né il Dispose(bool) finalizzatore della classe di base.

Violazione di uno di questi criteri attiva l'avviso CA1063.

Ogni tipo non bloccato che dichiara e implementa l'interfaccia IDisposable deve fornire il proprio protected virtual void Dispose(bool) metodo. Dispose() deve chiamare Dispose(true)e il finalizzatore deve chiamare Dispose(false). Se si crea un tipo non bloccato che dichiara e implementa l'interfaccia IDisposable , è necessario definirlo Dispose(bool) e chiamarlo. Per altre informazioni, vedere Pulire le risorse non gestite (guida .NET) e Implementare un metodo Dispose.

Per impostazione predefinita, questa regola esamina solo i tipi visibili esternamente, ma è configurabile.

Descrizione regola

Tutti i IDisposable tipi devono implementare correttamente il modello Dispose.

Come correggere le violazioni

Esaminare il codice e determinare quali delle risoluzioni seguenti correggeranno questa violazione:

  • Rimuovere IDisposable dall'elenco di interfacce implementate dal tipo ed eseguire l'override dell'implementazione Dispose della classe di base.

  • Rimuovere il finalizzatore dal tipo, eseguire l'override di Dispose(bool disposing) e inserire la logica di finalizzazione nel percorso del codice in cui 'disposing' è false.

  • Eseguire l'override di Dispose(bool disposing) e inserire la logica dispose nel percorso del codice in cui 'disposing' è true.

  • Assicurarsi che Dispose() sia dichiarato come pubblico e sealed.

  • Rinominare il metodo dispose in Dispose e assicurarsi che sia dichiarato come pubblico e sealed.

  • Assicurarsi che Dispose(bool) sia dichiarato come protetto, virtuale e non bloccato.

  • Modificare Dispose() in modo che chiami Dispose(true), quindi chiama SuppressFinalize sull'istanza dell'oggetto corrente (thiso Me in Visual Basic) e quindi restituisce .

  • Modificare il finalizzatore in modo che chiami Dispose(false) e quindi restituisca.

  • Se si crea un tipo non bloccato che dichiara e implementa l'interfaccia IDisposable , assicurarsi che l'implementazione di IDisposable segua il modello descritto in precedenza in questa sezione.

Quando eliminare gli avvisi

Non escludere un avviso da questa regola.

Nota

Se si applicano tutti gli avvisi seguenti, è possibile che vengano visualizzati avvisi falsi positivi da questa regola:

  • Si usa Visual Studio 2022 versione 17.5 o successiva con una versione precedente di .NET SDK, ovvero .NET 6 o versioni precedenti.
  • Si usano gli analizzatori di .NET 6 SDK o una versione precedente dei pacchetti analizzatori, ad esempio Microsoft.CodeAnalysis.FxCopAnalyzers.
  • Sono disponibili attributi per l'implementazione IDispose .

In questo caso, è possibile eliminare un avviso falso positivo. I falsi positivi sono dovuti a una modifica che causa un'interruzione nel compilatore C#. Prendere in considerazione l'uso di un analizzatore più recente che contiene la correzione per gli avvisi falsi positivi. Eseguire l'aggiornamento a Microsoft.CodeAnalysis.NetAnalyzers versione 7.0.0-preview1.22464.1 o successiva o usare gli analizzatori di .NET 7 SDK.

Configurare il codice da analizzare

Usare l'opzione seguente per configurare le parti della codebase in cui eseguire questa regola.

È possibile configurare questa opzione solo per questa regola, per tutte le regole a cui si applica o per tutte le regole in questa categoria (Progettazione) a cui si applica. Per altre informazioni, vedere Opzioni di configurazione delle regole di qualità del codice.

Includere superfici API specifiche

È possibile configurare le parti della codebase in modo da eseguire questa regola in base all'accessibilità. Ad esempio, per specificare che la regola deve essere eseguita solo sulla superficie dell'API non pubblica, aggiungere la coppia chiave-valore seguente a un file con estensione editorconfig nel progetto:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Esempio di pseudo-codice

Lo pseudo-codice seguente fornisce un esempio generale di come Dispose(bool) implementare in una classe che usa risorse gestite e native.

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

Vedi anche