Compartilhar via


CA1063: Implementar IDisposable corretamente

Property Valor
ID da regra CA1063
Título Implementar IDisposable corretamente
Categoria Projetar
Correção interruptiva ou sem interrupção Sem interrupção
Habilitado por padrão no .NET 9 Não

Causa

A interface System.IDisposable não está implementada corretamente. Os possíveis motivos para tanto incluem:

  • IDisposable é reimplementado na classe.
  • Finalize é substituído novamente.
  • Dispose() é substituído.
  • O método Dispose() não é público, selado ou chamado Descarte.
  • Dispose(bool) não é protegido, virtual ou não selado.
  • Em tipos não selados, Dispose() deve chamar Dispose(true).
  • Para tipos não selados, a implementação Finalize não chama nem Dispose(bool) nem o finalizador de classe base.

A violação de qualquer um desses padrões dispara o aviso CA1063.

Cada tipo não selado que declara e implementa a interface IDisposable deve fornecer seu próprio método protected virtual void Dispose(bool). Dispose() deve chamar Dispose(true) e o finalizador deve chamar Dispose(false). Se você criar um tipo não selado que declare e implemente a interface IDisposable, você deve definir Dispose(bool) e chamá-lo. Para obter mais informações, confira Limpar recursos não gerenciados (guia do .NET) e Implementar um método de Descarte.

Por padrão, essa regra apenas analisa os tipos visíveis externamente, mas isso é configurável.

Descrição da regra

Todos os tipos IDisposable devem implementar o padrão de Descarte corretamente.

Como corrigir violações

Examine seu código e determine quais das seguintes resoluções corrigirão essa violação:

  • Remova IDisposable da lista de interfaces que são implementadas pelo seu tipo e substitua a implementação do Descarte da classe base.

  • Remova o finalizador do seu tipo, substitua Dispose(bool disposing) e coloque a lógica de finalização no caminho do código onde "disposing" é false.

  • Substitua Dispose(bool disposing) e coloque a lógica de descarte no caminho do código em que 'disposing' é true.

  • Verifique se Dispose() é declarado como público e selado.

  • Renomeie o método de descarte para Dispose e verifique se ele é declarado como público e selado.

  • Verifique se Dispose(bool) é declarado como protegido, virtual e não selado.

  • Modifique Dispose() para que ele chame Dispose(true) e, em seguida, chame SuppressFinalize na instância do objeto atual (this ou Me no Visual Basic) e retorne.

  • Modifique seu finalizador para que ele chame Dispose(false) e retorne.

  • Se você criar um tipo não selado que declare e implemente a interface IDisposable, verifique se a implementação de IDisposable segue o padrão descrito anteriormente nesta seção.

Quando suprimir avisos

Não suprima um aviso nessa regra.

Observação

Você pode ver avisos de falsos positivos desta regra se todos os itens a seguir se aplicarem:

  • Você está usando o Visual Studio 2022 versão 17.5 ou posterior com uma versão mais antiga do SDK do .NET, ou seja, .NET 6 ou anterior.
  • Você está usando os analisadores do SDK do .NET 6 ou uma versão mais antiga dos pacotes do analisador, como Microsoft. CodeAnalysis.FxCopAnalyzers.
  • Você tem atributos na implementação do IDispose.

Nesse caso, é seguro suprimir um aviso falso positivo. Os falsos positivos são devido a uma alteração interruptiva no compilador de C#. Considere usar um analisador mais recente que contenha a correção para os avisos de falsos positivos. Atualize para Microsoft. CodeAnalysis.NetAnalyzers versão 7.0.0-preview1.22464.1 ou mais recente, ou use os analisadores do SDK do .NET 7.

Configurar código para analisar

Use a opção a seguir para configurar em quais partes da base de código essa regra deve ser executada.

Você pode configurar essa opção apenas para essa regra, para todas as regras às quais ela se aplica ou para todas as regras nessa categoria (Design) às quais ela se aplica. Para saber mais, confira Opções de configuração de regra de qualidade de código.

Incluir superfícies de API específicas

É possível configurar em quais partes da base de código essa regra deverá ser executada, com base na acessibilidade. Por exemplo, para especificar que a regra deverá ser executada apenas na superfície de API não pública, adicione o seguinte par chave-valor a um arquivo .editorconfig no projeto:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Exemplos de pseudocódigo

O pseudocódigo a seguir fornece um exemplo geral de como o Dispose(bool) deve ser implementado em uma classe que usa recursos gerenciados e nativos.

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

Confira também