CA1063: Implementar IDisposable corretamente

Propriedade valor
ID da regra CA1063
Cargo Implementar IDisposable corretamente
Categoria Desenho
A correção está quebrando ou não quebrando Sem quebra
Habilitado por padrão no .NET 8 Não

Causa

A System.IDisposable interface não está implementada corretamente. Possíveis razões para isso incluem:

  • IDisposable é reimplementado na classe.
  • Finalize é novamente anulada.
  • Dispose() é anulada.
  • O Dispose() método não é público, selado ou chamado Dispose.
  • Dispose(bool) não está protegido, virtual ou sem lacre.
  • Em tipos não lacrados, Dispose() deve chamar Dispose(true).
  • Para tipos sem lacre, a Finalize implementação não chama um ou ambos Dispose(bool) ou o finalizador de classe base.

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

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

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

Descrição da regra

Todos os IDisposable tipos devem implementar o padrão Dispose corretamente.

Como corrigir violações

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

  • Remova IDisposable da lista de interfaces que são implementadas pelo seu tipo e substitua a classe base Dispose implementation em vez disso.

  • 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 dispose no caminho do código onde 'disposing' é true.

  • Certifique-se de que Dispose() é declarado como público e selado.

  • Renomeie seu método de descarte para Eliminar e certifique-se de que ele seja declarado como público e lacrado.

  • Certifique-se de que Dispose(bool) está declarado como protegido, virtual e sem lacre.

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

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

  • Se você criar um tipo sem lacre que declare e implemente a interface, certifique-se de que a IDisposable implementação do IDisposable segue o padrão descrito anteriormente nesta seção.

Quando suprimir avisos

Não suprima um aviso desta regra.

Nota

Poderá ver avisos falsos positivos desta regra se se aplicarem todas as seguintes condições:

  • 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 em sua IDispose implementação.

Neste caso, é seguro suprimir um aviso falso positivo. Os falsos positivos são devidos a uma mudança de quebra no compilador C#. Considere o uso de 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 análise

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

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

Incluir superfícies de API específicas

Você pode configurar em quais partes da sua base de código executar essa regra, com base em sua acessibilidade. Por exemplo, para especificar que a regra deve ser executada somente na superfície de API não pública, adicione o seguinte par chave-valor a um arquivo .editorconfig em seu projeto:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Exemplo de pseudocódigo

O pseudocódigo a seguir fornece um exemplo geral de como 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);
    }
}

Consulte também