CA2213:应释放可释放的字段

属性
规则 ID CA2213
标题 应释放可释放的字段
类别 使用情况
修复是中断修复还是非中断修复 非中断
在 .NET 8 中默认启用

原因

实现 System.IDisposable 的类型声明具有同样实现 IDisposable 的类型的字段。 字段的 Dispose 方法不由声明类型的 Dispose 方法调用。

规则说明

类型负责释放其所有非托管资源。 规则 CA2213 检查可释放类型(即实现 IDisposable 的类型)T 是否声明字段 F(可释放类型 FT 的实例)。 对于分配了具有包含类型 T 的方法或初始化表达式中的本地创建对象的每个字段 F,该规则都会尝试查找对 FT.Dispose 的调用。 该规则搜索 T.Dispose 调用的方法和下一级方法(即,由 T.Dispose 调用的方法调用的方法)。

注意

特殊情况外,规则 CA2213 仅针对分配了包含类型的方法和初始化表达式中的本地创建可释放对象的字段触发。 如果对象在类型 T 之外创建或分配,则该规则不会触发。 对于包含类型不负责释放对象的情况,这可以减少干扰。

特殊情况

即使分配的对象未在本地创建,规则 CA2213 也会针对以下类型的字段触发:

将其中一种类型的对象传递给构造函数,然后将其分配到某个字段,可指示释放所有权转移到新构造的类型。 也就是说,新构造的类型现在负责释放对象。 如果未释放对象,则会发生 CA2213 冲突。

如何解决冲突

若要解决此规则的冲突,请在具有实现 IDisposable 的类型的字段上调用 Dispose

何时禁止显示警告

在以下情况下,禁止显示此规则的警告是安全的:

  • 标记的类型不负责释放字段占用的资源(即,该类型不具有释放所有权)
  • 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);
    }
}

以下代码片段显示类型 TypeB,它因为将字段 aFieldOfADisposableType 声明为可释放类型 (TypeA) 且没有在该字段上调用 Dispose 而与规则 CA2213 冲突。

public class TypeB : IDisposable
{
    // Assume this type has some unmanaged resources.
    TypeA aFieldOfADisposableType = new TypeA();
    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);
      }
   }
}

另请参阅