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

注意

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

虛擬程式碼範例

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

另請參閱