CA1063: IDisposable korrekt implementieren.

Eigenschaft Wert
Regel-ID CA1063
Titel IDisposable korrekt implementieren.
Kategorie Design
Fix führt oder führt nicht zur Unterbrechung Nicht unterbrechend
Standardmäßig in .NET 8 aktiviert Nein

Ursache

Die System.IDisposable-Schnittstelle ist nicht ordnungsgemäß implementiert. Dies kann folgende Ursachen haben:

  • IDisposable wurde in der Klasse reimplementiert.
  • Finalize wird erneut überschrieben.
  • Dispose() wurde überschrieben.
  • Die Dispose()-Methode ist nicht öffentlich, versiegeltoder wurde Verworfen benannt.
  • Dispose(bool) ist nicht geschützt, virtuell oder nicht versiegelt.
  • In nicht versiegelten Typen muss Dispose()Dispose(true) aufrufen.
  • Bei nicht versiegelten Typen ruft die Finalize-Implementierung weder Dispose(bool) noch den Basisklassen-Finalizer auf.

Ein Verstoß gegen eines dieser Muster löst die Warnung CA1063 aus.

Jeder nicht versiegelte Typ, der die IDisposable-Schnittstelle deklariert und implementiert, muss eine eigene protected virtual void Dispose(bool)-Methode bereitstellen. Dispose() sollte Dispose(true) aufrufen, und der Finalizer sollte Dispose(false) aufrufen. Wenn Sie einen nicht versiegelten Typ erstellen, der die IDisposable-Schnittstelle deklariert und implementiert, müssen Sie Dispose(bool) definieren und aufrufen. Weitere Informationen finden Sie unter Bereinigen nicht verwalteter Ressourcen (.NET-Handbuch) und Implementieren einer Dispose-Methode.

Standardmäßig werden mit dieser Regel nur extern sichtbare Typen überprüft, aber dies ist konfigurierbar.

Regelbeschreibung

Alle IDisposable-Typen sollten das Dispose-Muster korrekt implementieren.

Behandeln von Verstößen

Überprüfen Sie Ihren Code, und legen Sie fest, welche der folgenden Auflösungen diese Verletzung beheben soll:

  • Entfernen Sie IDisposable aus der Liste der Schnittstellen, die von Ihrem Typ implementiert werden, und überschreiben Sie stattdessen die Implementierung der Dispose-Basisklasse.

  • Entfernen Sie den Finalizer aus dem Typ, überschreiben Sie Dispose (bool disposing), und platzieren Sie die Finalisierungslogik in den Codepfad, in dem „disposing“ FALSE lautet.

  • Überschreiben Sie Dispose (bool disposing), und platzieren Sie die Dispose-Logik im Codepfad, wenn „disposing“ TRUE lautet.

  • Stellen Sie sicher, dass Dispose() als öffentlich und versiegeltdeklariert ist.

  • Benennen Sie Ihre Methode aufDispose um und stellen Sie sicher, dass Sie als öffentlich und versiegelt deklariert ist.

  • Stellen Sie sicher, dass Dispose(bool) als geschützt, virtuell und nicht versiegelt deklariert ist.

  • Ändern Sie Dispose() so, dass Dispose(true) aufgerufen wird, und dann SuppressFinalize auf der aktuellen Objektinstanz aufgerufen wird (this oder Me in Visual Basic), und dann zurückgegeben wird.

  • Ändern Sie Ihren Finalizer so, dass Dispose(false) aufgerufen und anschließend ein Wert zurückgegeben wird.

  • Wenn Sie einen nicht versiegelten Typ erstellen, der die IDisposable-Schnittstelle deklariert und implementiert, stellen Sie sicher, dass die Implementierung von IDisposable dem zuvor in diesem Abschnitt beschriebenen Muster folgt.

Wann sollten Warnungen unterdrückt werden?

Unterdrücken Sie keine Warnung dieser Regel.

Hinweis

Möglicherweise werden falsch positive Warnungen von dieser Regel angezeigt, wenn alle der folgenden Punkte zutreffen:

  • Sie verwenden Visual Studio 2022, Version 17.5 oder höher, mit einer älteren Version des .NET SDK, d. h. .NET 6 oder früher.
  • Sie verwenden die Analysetools aus dem .NET 6 SDK oder einer älteren Version der Analysetoolpakete, z. B. Microsoft. CodeAnalysis.FxCopAnalyzers.
  • Sie verwenden Attribute für Ihre IDispose-Implementierung.

In diesem Fall ist es unproblematisch, eine falsch positive Warnung zu unterdrücken. Die falsch positiven Warnungen sind auf einen Breaking Change im C#-Compiler zurückzuführen. Erwägen Sie die Verwendung von neueren Analysetools, die den Hotfix für falsch positive Warnungen enthalten. Führen Sie ein Upgrade auf Microsoft. CodeAnalysis.NetAnalyzers Version 7.0.0-preview1.22464.1 oder höher aus, oder verwenden Sie die Analysetools aus dem .NET 7 SDK.

Konfigurieren des zu analysierenden Codes

Mithilfe der folgenden Option können Sie konfigurieren, für welche Teile Ihrer Codebasis diese Regel ausgeführt werden soll.

Sie können diese Optionen nur für diese Regel, für alle zutreffenden Regeln oder für alle zutreffenden Regeln in dieser Kategorie (Entwurf) konfigurieren. Weitere Informationen finden Sie unter Konfigurationsoptionen für die Codequalitätsregel.

Einschließen bestimmter API-Oberflächen

Sie können je nach Zugänglichkeit festlegen, für welche Bestandteile Ihrer Codebasis diese Regel ausgeführt wird. Sie können beispielsweise festlegen, dass die Regel nur für die nicht öffentliche API-Oberfläche ausgeführt werden soll, indem Sie einer EDITORCONFIG-Datei in Ihrem Projekt das folgende Schlüssel-Wert-Paar hinzufügen:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Pseudocodebeispiel

Der folgende Pseudocode bietet ein allgemeines Beispiel dafür, wie Dispose(bool) in einer Klasse implementiert werden sollte, die verwaltete und native Ressourcen verwendet.

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

Siehe auch