CA2213: Campos descartáveis devem ser descartados

Property Valor
ID da regra CA2213
Título Campos descartáveis devem ser descartados
Categoria Usage
Correção interruptiva ou sem interrupção Sem interrupção
Habilitado por padrão no .NET 8 Não

Causa

Um tipo que implementa System.IDisposable declara campos que são de tipos que também implementam IDisposable. O método Dispose do campo não é chamado pelo método Dispose do tipo declarante.

Descrição da regra

Um tipo é responsável por descartar todos os recursos não gerenciados. A regra CA2213 verifica se um tipo descartável (ou seja, aquele que implementa IDisposable) T declara um campo F que é uma instância de um tipo descartável FT. Para cada campo F atribuído a um objeto criado localmente dentro dos métodos ou inicializadores do tipo contido T, a regra tentará localizar uma chamada para FT.Dispose. A regra pesquisa os métodos chamados por T.Dispose e um nível inferior (ou seja, os métodos chamados pelos métodos chamados por T.Dispose).

Observação

Além dos casos especiais, a regra CA2213 é acionada apenas para campos que são atribuídos a um objeto descartável criado localmente nos métodos e inicializadores do tipo que o contém. Se o objeto for criado ou atribuído fora do tipo T, a regra não será acionada. Isso reduz o ruído nos casos em que o tipo que o contém não possui a responsabilidade de descartar o objeto.

Casos especiais

A regra CA2213 também poderá ser acionada para campos dos seguintes tipos, mesmo que o objeto atribuído não seja criado localmente:

Passar um objeto de um desses tipos para um construtor e depois atribuí-lo a um campo indica uma transferência de propriedade de descarte para o tipo recém-construído. Ou seja, o tipo recém-construído agora será o responsável por descartar o objeto. Se o objeto não for descartado, ocorrerá uma violação de CA2213.

Como corrigir violações

Para corrigir uma violação dessa regra, chame Dispose em campos que sejam de tipos que implementam IDisposable.

Quando suprimir avisos

É seguro suprimir um aviso dessa regra se:

  • O tipo sinalizado não é responsável por liberar o recurso retido pelo campo (ou seja, o tipo não possui propriedade de descarte)
  • A chamada para Dispose ocorrerá em um nível de chamada mais profundo do que as verificações de regra
  • se a propriedade de descarte do(s) campo(s) não for mantida pelo tipo de contenção.

Suprimir um aviso

Para suprimir apenas uma violação, adicione diretivas de pré-processador ao arquivo de origem a fim de desabilitar e, em seguida, reabilitar a regra.

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

Para desabilitar a regra em um arquivo, uma pasta ou um projeto, defina a severidade como none no arquivo de configuração.

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

Para obter mais informações, confira Como suprimir avisos de análise de código.

Exemplo

O snippet a seguir mostra um tipo TypeA que implementa IDisposable.

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);
    }
}

O snippet a seguir mostra um tipo TypeB que viola a regra CA2213 declarando um campo aFieldOfADisposableType como um tipo descartável (TypeA) e não chamando Dispose no campo.

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);
    }
}

Para corrigir a violação, chame Dispose() no campo descartável:

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);
      }
   }
}

Confira também