CA1063: Implementuje správně IDisposable

Vlastnost Hodnota
ID pravidla CA1063
Název Implementuje správně IDisposable
Kategorie Návrh
Oprava způsobující chybu nebo chybu způsobující chybu Nenarušující
Povoleno ve výchozím nastavení v .NET 8 No

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řepsaný.
  • 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 ani oba 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 IDisposable rozhraní, musíte ho definovat Dispose(bool) a volat. 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 přepište implementaci základní třídy Dispose.

  • Odeberte finalizační metodu z vašeho typu, přepište Dispose(bool disposing) a vložte logiku finalizace do cesty kódu, kde 'disposing' je false.

  • Override Dispose(bool disposing) and put the dispose logic in the code path where 'disposing' is true.

  • 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 aktuální instanci objektu (thisnebo Me v jazyce Visual Basic) a pak vrátí.

  • Upravte finalizátor tak, aby volil 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

Na základě přístupnosti můžete nakonfigurovat, na kterých částech základu kódu se má toto pravidlo spouštět. 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

Příklad pseudokódu

Následující pseudokód poskytuje obecný příklad způsobu Dispose(bool) implementace ve třídě, která použí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é