CA1063:必須正確實作 IDisposable

屬性
規則識別碼 CA1063
職稱 必須正確實作 IDisposable
類別 設計
修正是造成中斷還是不中斷 不中斷
在 .NET 10 中預設啟用
適用語言 C# 與 Visual Basic

原因

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) 並呼叫它。 如需詳細資訊,請參閱 清除未管理的資源(.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),在 Visual Basic 中則呼叫 Me,然後返回。

  • 修改您的終結器,使其呼叫 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_surface] 選項,根據程式代碼基底的存取範圍,設定執行此規則的哪些部分。 例如,若要指定規則只應該針對非公用 API 介面執行,請將下列機碼/值組新增至 專案中的 .editorconfig 檔案:

dotnet_code_quality.CAXXXX.api_surface = private, internal

注意

以適用規則的標識碼取代 XXXXCAXXXX 部分。

虛擬程式碼範例

以下的偽代碼提供了一個一般範例,說明如何在使用 "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);
    }
}

另請參閱