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()
volatDispose(true)
. - Pro nezapečetěné typy
Finalize
implementace nevolá ani ani obaDispose(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 (
this
neboMe
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);
}
}