CA1063: Implementujte správně IDisposable

Vlastnost Hodnota
ID pravidla CA1063
Název Implementujte IDisposable správně
Kategorie Návrh
Oprava, která může být destruktivní nebo nedestruktivní Nezlomitelný
Povoleno ve výchozím nastavení v .NET 10 Ne
Příslušné jazyky C# a Visual Basic

Příčina

Rozhraní System.IDisposable není implementováno správně. Mezi možné důvody patří:

  • IDisposable je reimplementován ve třídě.
  • Finalize je přepsaný znovu.
  • Dispose() je přepsáno.
  • Metoda Dispose() není veřejná, zapečetěná nebo pojmenovaná Dispose.
  • Dispose(bool) není chráněn, virtuální ani nezapečetěný.
  • V nezapečetěných typech musí Dispose() volat Dispose(true).
  • Pro nezapečetěné typy Finalize implementace nevolá ani Dispose(bool), ani finalizátor základní třídy.

Porušení některého z těchto vzorů aktivuje upozornění CA1063.

Každý nezapečetěný typ, který deklaruje a implementuje IDisposable rozhraní, musí poskytovat vlastní protected virtual void Dispose(bool) metodu. Dispose() by měla volat Dispose(true), a finalizátor by měl volat Dispose(false). Pokud vytvoříte nezapečetěný typ, který deklaruje a implementuje rozhraní IDisposable, musíte definovat Dispose(bool) a toto volání provést. Další informace naleznete v tématu Vyčištění nespravovaných prostředků (průvodce .NET) a Implementace metody Dispose.

Ve výchozím nastavení toto pravidlo sleduje jenom externě viditelné typy, ale dá se konfigurovat.

Popis pravidla

Všechny IDisposable typy by měly správně implementovat vzor Dispose.

Jak opravit porušení

Prozkoumejte kód a určete, která z následujících řešení toto porušení opraví:

  • Odeberte IDisposable ze seznamu rozhraní, která jsou implementována vaším typem, a místo toho přepište implementaci metody Dispose v základní třídě.

  • Odeberte finalizér z vašeho typu, přepište Dispose(bool disposing) a umístěte logiku finalizace do části kódu, kde je 'disposing' rovno false.

  • Přepište metodu Dispose(bool disposing) a vložte logiku pro uvolnění do části kódu, kde je 'disposing' pravda.

  • Ujistěte se, že dispose() je deklarována jako veřejná a zapečetěná.

  • Přejmenujte metodu dispose na Dispose a ujistěte se, že je deklarována jako veřejná a zapečetěná.

  • Ujistěte se, že dispose(bool) je deklarován jako chráněný, virtuální a nezapečetěný.

  • Upravte Dispose() tak, aby volal Dispose(true), pak volá SuppressFinalize na aktuální instanci objektu (this, nebo Me v jazyce Visual Basic), a pak se vrátí.

  • Upravte finalizátor tak, aby zavolal Dispose(false) a pak se vrátil.

  • Pokud vytvoříte nezapečetěný typ, který deklaruje a implementuje IDisposable rozhraní, ujistěte se, že implementace IDisposable následuje vzor popsaný výše v této části.

Kdy potlačit upozornění

Nepotlačujte upozornění na toto pravidlo.

Poznámka:

Falešně pozitivní upozornění z tohoto pravidla se můžou zobrazit, pokud platí všechny tyto skutečnosti:

  • Používáte Sadu Visual Studio 2022 verze 17.5 nebo novější se starší verzí sady .NET SDK, tj. .NET 6 nebo starší.
  • Používáte analyzátory ze sady .NET 6 SDK nebo starší verze balíčků analyzátoru, například Microsoft.CodeAnalysis.FxCopAnalyzers.
  • Ve své IDispose implementaci máte atributy.

V tomto případě je bezpečné potlačit falešně pozitivní upozornění. Falešně pozitivní výsledky jsou způsobeny zásadní změnou kompilátoru jazyka C#. Zvažte použití novějšího analyzátoru, který obsahuje opravu falešně pozitivních upozornění. Upgradujte na Microsoft.CodeAnalysis.NetAnalyzers verze 7.0.0-preview1.22464.1 nebo novější nebo použijte analyzátory ze sady .NET 7 SDK.

Konfigurace kódu pro analýzu

Pomocí následující možnosti nakonfigurujte, ve kterých částech základu kódu se má toto pravidlo spouštět.

Tuto možnost můžete nakonfigurovat jenom pro toto pravidlo, pro všechna pravidla, která platí, nebo pro všechna pravidla v této kategorii (Návrh), na která platí. Další informace naleznete v tématu Možnosti konfigurace pravidla kvality kódu.

Zahrnutí konkrétních povrchů rozhraní API

Nastavením možnosti api_surface můžete nakonfigurovat, na kterých částech základu kódu se má toto pravidlo spouštět na základě jejich přístupnosti. Pokud chcete například určit, že pravidlo by se mělo spouštět jenom na neveřejné ploše rozhraní API, přidejte do souboru .editorconfig v projektu následující pár klíč-hodnota:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Poznámka:

Nahraďte XXXX část CAXXXX ID příslušného pravidla.

Příklad pseudokódu

Následující pseudokód poskytuje obecný příklad toho, jak by mělo být Dispose(bool) implementováno ve třídě, jež využívá spravované a nativní prostředky.

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

Viz také