CA1063: Implementar IDisposable correctamente

Propiedad Value
Identificador de la regla CA1063
Título Implementar IDisposable correctamente
Categoría Diseño
La corrección es problemática o no problemática Poco problemático
Habilitado de forma predeterminada en .NET 8 No

Causa

La interfaz System.IDisposable no se ha implementado correctamente. Entre las posibles razones se incluyen las siguientes:

  • Se ha implementado IDisposable en la clase.
  • Se ha vuelto a invalidar Finalize.
  • Se ha invalidado Dispose().
  • El método Dispose() no es público, sellado ni tiene el nombre Dispose.
  • Dispose(bool) no está protegido ni es virtual o no sellado.
  • En los tipos no sellados, Dispose() debe llamar a Dispose(true).
  • En el caso de los tipos no sellados, la implementación Finalize no llama ni a Dispose(bool) ni al finalizador de la clase base.

La infracción de cualquiera de estos patrones desencadena una advertencia CA1063.

Cada tipo no sellado que declara e implementa la interfaz IDisposable debe proporcionar su propio método protected virtual void Dispose(bool). Dispose() debe llamar a Dispose(true) y el finalizador debe llamar a Dispose(false). Si crea un tipo no sellado que declara e implementa la interfaz IDisposable, debe definir Dispose(bool) y llamarlo. Para más información, consulte Limpieza de recursos no administrados e IMplementación de un modelo de eliminación.

De forma predeterminada, esta regla solo examina los tipos visibles externamente, pero es configurable.

Descripción de la regla

Todos los tipos IDisposable deben implementar el modelo de eliminación correctamente.

Cómo corregir infracciones

Examine el código y determine cuál de las siguientes soluciones corregirá esta infracción:

  • Quite IDisposable de la lista de interfaces que implementa el tipo e invalide la implementación de Dispose de la clase base.

  • Quite el finalizador del tipo, invalide Dispose(bool disposing) y coloque la lógica de finalización en la ruta de acceso al código de manera que "disposing" se establezca en "false".

  • Invalide Dispose(bool disposing) y coloque la lógica de eliminación en la ruta de acceso al código de manera que "disposing" se establezca en "true".

  • Asegúrese de que Dispose() se declara como público y sellado.

  • Cambie el nombre del método de eliminación a Dispose y asegúrese de que se declara como público y sellado.

  • Asegúrese de que Dispose(bool) se declara como protegido, virtual y no sellado.

  • Modifique Dispose() para que llame a Dispose(true) y, después, a SuppressFinalize en la instancia de objeto actual (this, o Me en Visual Basic) y, luego, vuelva.

  • Modifique el finalizador para que llame a Dispose(false) y, luego, devuelva un valor.

  • Si crea un tipo no sellado que declara e implementa la interfaz IDisposable, asegúrese de que la implementación de IDisposable sigue el modelo descrito anteriormente en esta sección.

Cuándo suprimir las advertencias

No suprima las advertencias de esta regla.

Nota

Es posible que vea advertencias de falsos positivos de esta regla si se aplica todo lo siguiente:

  • Está usando Visual Studio 2022, versión 17.5 o posterior, con una versión anterior del SDK de .NET, es decir, .NET 6 o una anterior.
  • Está usando los analizadores del SDK de .NET 6 o una versión anterior de los paquetes del analizador, como Microsoft.CodeAnalysis.FxCopAnalyzers.
  • Tiene atributos en la implementación de IDispose.

En este caso, es seguro suprimir una advertencia de falso positivo. Los falsos positivos se deben a un cambio importante en el compilador de C#. Considere la posibilidad de usar un analizador más reciente que incluya la corrección de las advertencias de falsos positivos. Actualice a Microsoft.CodeAnalysis.NetAnalyzers, versión 7.0.0-preview1.22464.1 o posterior, o bien use los analizadores del SDK de .NET 7.

Configuración del código para analizar

Use la opción siguiente para configurar en qué partes del código base ejecutar esta regla.

Puede configurar esta opción solo para esta regla, para todas las reglas a las que se aplica o para todas las reglas de esta categoría (Diseño) a las que se aplica. Para más información, vea Opciones de configuración de reglas de calidad de código.

Incluir superficies de API específicas

Puede configurar en qué partes del código base ejecutar esta regla, en función de su accesibilidad. Por ejemplo, para especificar que la regla solo se debe ejecutar en la superficie de API no públicas, agregue el siguiente par clave-valor a un archivo .editorconfig en el proyecto:

dotnet_code_quality.CAXXXX.api_surface = private, internal

Ejemplo de pseudocódigo

El pseudocódigo siguiente proporciona un ejemplo general de cómo se debe implementar Dispose(bool) en una clase que usa recursos administrados y 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 también