分享方式:


CA1063:必須正確實作 IDisposable

屬性
規則識別碼 CA1063
標題 必須正確實作 IDisposable
類別 設計
修正程式是中斷或非中斷 不中斷
預設在 .NET 8 中啟用 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),然後在目前的物件實例上呼叫 SuppressFinalizethis或在 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);
    }
}

另請參閱