CA1063:必須正確實作 IDisposable
屬性 | 值 |
---|---|
規則識別碼 | CA1063 |
職稱 | 必須正確實作 IDisposable |
類別 | 設計 |
修正程式是中斷或非中斷 | 不中斷 |
預設在 .NET 9 中啟用 | No |
原因
System.IDisposable介面未正確實作。 可能的原因包括:
- IDisposable 會在類別中重新實作。
Finalize
會再次覆寫。Dispose()
已覆寫。- 方法
Dispose()
不是公用、 密封或具名 Dispose。 Dispose(bool)
未受到保護、虛擬或未密封。- 在未密封的類型中,
Dispose()
必須呼叫Dispose(true)
。 - 針對未密封的類型,實
Finalize
作不會呼叫 或基Dispose(bool)
類完成項。
違反上述任一模式會觸發警告 CA1063。
宣告並實 IDisposable 作介面的每個未密封類型都必須提供自己的 protected virtual void Dispose(bool)
方法。 Dispose()
應該呼叫 Dispose(true)
,而完成項目應該呼叫 Dispose(false)
。 如果您建立宣告並實 IDisposable 作 介面的未密封類型,則必須定義 Dispose(bool)
並呼叫它。 如需詳細資訊,請參閱 清除 Unmanaged 資源 (.NET 指南) 和 實作 Dispose 方法。
根據預設,此規則只會查看外部可見的類型,但這是可設定的。
檔案描述
所有 IDisposable 類型都應該 正確實作 Dispose 模式 。
如何修正違規
檢查您的程式代碼,並判斷下列哪一個解決方案會修正此違規:
請從類型實作的介面清單中移除 IDisposable ,並改為覆寫基類 Dispose 實作。
從您的類型中移除完成項、覆寫 Dispose(bool disposing),並將最終處理邏輯放在 'disposing' 為 false 的程式代碼路徑中。
覆寫 Dispose(bool disposing),並將處置邏輯放在 'disposing' 為 true 的程式代碼路徑中。
請確定 Dispose() 已宣告為公用和 密封。
將處置方法重新命名為 Dispose ,並確定其宣告為公用和 密封。
請確定 Dispose(bool) 宣告為受保護、虛擬和未密封。
修改 Dispose(),讓它呼叫 Dispose(true),然後在目前的物件實例上呼叫 SuppressFinalize ,
this
或在Me
Visual Basic 中呼叫 ,然後傳回 。修改完成項,使其呼叫 Dispose(false),然後傳回。
如果您建立宣告並實 IDisposable 作 介面的未密封類型,請確定的 IDisposable 實作遵循本節稍早所述的模式。
隱藏警告的時機
請勿隱藏此規則的警告。
注意
如果適用下列所有專案,您可能會看到來自此規則的誤判警告:
- 您使用 Visual Studio 2022 17.5 版或更新版本搭配舊版 .NET SDK,也就是 .NET 6 或更早版本。
- 您使用的是 .NET 6 SDK 或舊版分析器套件的分析器,例如 Microsoft.CodeAnalysis.FxCopAnalyzers。
- 您在實
IDispose
作上有屬性。
在此情況下,可以放心地隱藏誤判警告。 誤判是由於 C# 編譯程式中的重大變更所造成。 請考慮使用包含誤判警告修正的較新分析器。 升級至 Microsoft.CodeAnalysis.NetAnalyzers 7.0.0-preview1.22464.1 版或更新版本,或使用 .NET 7 SDK 的分析器。
設定程式代碼以分析
使用下列選項來設定程式代碼基底要執行此規則的部分。
您可以只針對此規則、針對它套用的所有規則,或針對套用至此類別的所有規則,或針對它套用的所有規則,設定此選項。 如需詳細資訊,請參閱 程式代碼品質規則組態選項。
包含特定 API 介面
您可以根據程式代碼基底的存取範圍,設定要執行此規則的部分。 例如,若要指定規則只應該針對非公用 API 介面執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:
dotnet_code_quality.CAXXXX.api_surface = private, internal
虛擬程式碼範例
下列虛擬程式代碼提供如何在使用Managed和原生資源的類別中實作的 Dispose(bool)
一般範例。
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);
}
}