CA2213:可處置的欄位應該受到處置

屬性
規則識別碼 CA2213
職稱 需釋放的欄位應予以釋放
類別 使用方式
修正是造成中斷還是不中斷 不中斷
在 .NET 10 中預設啟用
適用語言 C# 與 Visual Basic

原因

實作 System.IDisposable 的型別宣告欄位,而這些欄位的型別也實作 IDisposable。 宣告型別的 Dispose 方法不會呼叫 Dispose 欄位的方法。

規則描述

類型負責處置所有其非受控資源。 規則 CA2213 會檢查一個可處置型別(即實作IDisposable的型別)T是否宣告一個欄位F,該欄位是可處置型別FT的實例。 針對在包含型別 T 的方法或初始化表達式內指派本機建立之物件的每個欄位 F,規則會嘗試尋找對 FT.Dispose 的呼叫。 規則會搜尋由 T.Dispose 呼叫的方法,以及更低一層的層級(也就是由這些方法所呼叫的 T.Dispose 方法)。

注意

除了 特殊案例之外,規則 CA2213 只會針對欄位在包含類型的方法和初始化器中被指派本機建立的可處置物件時引發。 如果物件是在類型 T之外建立或指派,則不會觸發規則。 這可以減少在包含類型不負責管理物件處置的情況下所產生的雜訊。

特殊情況

即使指派的物件不是在本地建立,規則 CA2213 仍會觸發在下列類型的欄位:

將其中一個型別的對象傳遞至建構函式,然後將它指派給字段,表示 處置擁有權傳送 至新建構的類型。 也就是說,新建立的類型現在負責銷毀該物件。 如果未處置物件,就會發生 CA2213 違規。

如何修正違規

若要修正此規則的違規,請在實作IDisposableDispose型別欄位上呼叫。

隱藏警告的時機

如果下列狀況,可以放心地隱藏此規則的警告:

  • 標記類型不負責釋放由欄位持有的資源(也就是類型沒有 處置擁有權
  • Dispose 的呼叫發生在比規則檢查更深的呼叫層級
  • 欄位的處置擁有權不是由包含的類型所持有。

隱藏警告

如果您只想要隱藏單一違規,請將預處理器指示詞新增至原始程式檔以停用,然後重新啟用規則。

#pragma warning disable CA2213
// The code that's violating the rule is on this line.
#pragma warning restore CA2213

若要停用檔案、資料夾或專案的規則,請在組態檔中將其嚴重性設為 none

[*.{cs,vb}]
dotnet_diagnostic.CA2213.severity = none

如需詳細資訊,請參閱 如何隱藏程式代碼分析警告

設定數據流分析

使用下列選項來設定此規則的資料串流分析:

您可以只針對此規則、套用至的所有規則,或套用至此類別的所有規則(安全性)設定這些選項。 如需詳細資訊,請參閱 程式代碼品質規則組態選項。

範例

下列代碼段顯示實作IDisposable的類型TypeA

public class TypeA : IDisposable
{
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Dispose managed resources
        }

        // Free native resources
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Disposable types implement a finalizer.
    ~TypeA()
    {
        Dispose(false);
    }
}

下列代碼段顯示違反規則 CA2213 的類型 TypeB ,方法是將字段 aFieldOfADisposableType 宣告為可處置類型 (TypeA), 而不是在欄位上呼叫 Dispose

public class TypeB : IDisposable
{
    // Assume this type has some unmanaged resources.
    TypeA aFieldOfADisposableType = new();
    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            // Dispose of resources held by this instance.

            // Violates rule: DisposableFieldsShouldBeDisposed.
            // Should call aFieldOfADisposableType.Dispose();

            disposed = true;
            // Suppress finalization of this disposed instance.
            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
        }
    }

    public void Dispose()
    {
        if (!disposed)
        {
            // Dispose of resources held by this instance.
            Dispose(true);
        }
    }

    // Disposable types implement a finalizer.
    ~TypeB()
    {
        Dispose(false);
    }
}

若要修正違規,請在可處置字段上呼叫 Dispose()

protected virtual void Dispose(bool disposing)
{
   if (!disposed)
   {
      // Dispose of resources held by this instance.
      aFieldOfADisposableType.Dispose();

      disposed = true;

      // Suppress finalization of this disposed instance.
      if (disposing)
      {
          GC.SuppressFinalize(this);
      }
   }
}

另請參閱