CA1816: Llamar a GC.SuppressFinalize correctamente
Propiedad | Value |
---|---|
Identificador de la regla | CA1816 |
Título | Llamar a GC.SuppressFinalize correctamente |
Categoría | Uso |
La corrección es problemática o no problemática | Poco problemático |
Habilitado de forma predeterminada en .NET 8 | Como sugerencia |
Causa
Las infracciones de esta regla pueden deberse a los factores siguientes:
En una clase no sealada, un método que es una implementación de IDisposable.Dispose y no llama a GC.SuppressFinalize.
Un método que no es una implementación de IDisposable.Dispose y llama a GC.SuppressFinalize.
Un método que llama a GC.SuppressFinalize y pasa un valor distinto de this (C#) o Me (Visual Basic).
Descripción de la regla
El método IDisposable.Dispose permite a los usuarios liberar recursos en cualquier momento antes de que el objeto esté disponible para la recolección de elementos no utilizados. Si se llama al método IDisposable.Dispose, este libera los recursos del objeto. Esto hace que la finalización sea innecesaria. IDisposable.Dispose debe llamar a GC.SuppressFinalize para que el recolector de elementos no utilizados no llame al finalizador del objeto.
Para evitar que los tipos derivados con finalizadores tengan que volver a implementar IDisposable y llamarlo, los tipos no sellados sin finalizadores deben seguir llamando a GC.SuppressFinalize.
Cómo corregir infracciones
Para corregir una infracción de esta regla haga lo siguiente:
Si el método es una implementación de Dispose, agregue una llamada a GC.SuppressFinalize.
Si el método no es una implementación de Dispose, quite la llamada a GC.SuppressFinalize o muévala a la implementación de Dispose del tipo.
Cambie todas las llamadas a GC.SuppressFinalize para pasar this (C#) o Me (Visual Basic).
Si el tipo no está diseñado para reemplazarse, márcalo como
sealed
.
Cuándo suprimir las advertencias
Solo debes suprimir una advertencia de esta regla si usa deliberadamente GC.SuppressFinalize para controlar la duración de otros objetos. No suprima una advertencia de esta regla si una implementación de Dispose no llama a GC.SuppressFinalize. En esta situación, el hecho de no suprimir la finalización degrada el rendimiento y no ofrece ninguna ventaja.
Supresión de una advertencia
Si solo quiere suprimir una única infracción, agregue directivas de preprocesador al archivo de origen para deshabilitar y volver a habilitar la regla.
#pragma warning disable CA1816
// The code that's violating the rule is on this line.
#pragma warning restore CA1816
Para deshabilitar la regla de un archivo, una carpeta o un proyecto, establezca su gravedad en none
del archivo de configuración.
[*.{cs,vb}]
dotnet_diagnostic.CA1816.severity = none
Para obtener más información, consulte Procedimiento para suprimir advertencias de análisis de código.
Ejemplo que infringe la regla CA1816
Este código muestra un método que llama a GC.SuppressFinalize, pero no pasa this (C#) ni Me (Visual Basic). Como resultado, este código infringe la regla CA1816.
Public Class DatabaseConnector
Implements IDisposable
Private _Connection As New SqlConnection
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
' Violates rules
GC.SuppressFinalize(True)
End Sub
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If _Connection IsNot Nothing Then
_Connection.Dispose()
_Connection = Nothing
End If
End If
End Sub
End Class
public class DatabaseConnector : IDisposable
{
private SqlConnection? _Connection = new SqlConnection();
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(true); // Violates rule
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_Connection != null)
{
_Connection.Dispose();
_Connection = null;
}
}
}
}
Ejemplo que cumple la regla CA1816
Este código muestra un método que llama correctamente a GC.SuppressFinalize pasando this (C#) o Me (Visual Basic).
Public Class DatabaseConnector
Implements IDisposable
Private _Connection As New SqlConnection
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If _Connection IsNot Nothing Then
_Connection.Dispose()
_Connection = Nothing
End If
End If
End Sub
End Class
public class DatabaseConnector : IDisposable
{
private SqlConnection? _Connection = new SqlConnection();
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_Connection != null)
{
_Connection.Dispose();
_Connection = null;
}
}
}
}
Reglas relacionadas
- CA2215: Los métodos Dispose deben llamar al método Dispose de la clase base
- CA2216: Los tipos descartables deben declarar el finalizador