CA2000: Desechar objetos antes de perder el ámbito
Propiedad | Value |
---|---|
Identificador de la regla | CA2000 |
Título | Desechar objetos antes de perder el ámbito |
Categoría | Confiabilidad |
La corrección es problemática o no problemática | Poco problemático |
Habilitado de forma predeterminada en .NET 8 | No |
Causa
Se crea un objeto local de un tipo IDisposable, pero el objeto no se elimina antes de que todas las referencias al mismo estén fuera de ámbito.
De forma predeterminada, esta regla analiza todo el código base, pero esto es configurable.
Descripción de la regla
Si un objeto que se puede eliminar (método Dispose) no se elimina de forma explícita antes de que todas las referencias a él estén fuera de ámbito, el objeto se eliminará en algún momento indeterminado cuando el recolector de elementos no utilizados ejecute el finalizador del objeto. Puesto que podría producirse un evento excepcional que impida que se ejecute el finalizador del objeto, el objeto debe eliminarse de forma explícita.
Casos especiales
La regla CA2000 no se activa para objetos locales de los siguientes tipos, aunque no se deseche el objeto:
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
Pasar un objeto de uno de estos tipos a un constructor y, después, asignarlo a un campo indica una transferencia de la propiedad Dispose hacia el tipo recién construido. Es decir, el tipo recién construido ahora es responsable de desechar el objeto. Si el código pasa un objeto de uno de estos tipos a un constructor, no se produce ninguna infracción de la regla CA2000 aunque no se elimine el objeto antes de que todas las referencias a él estén fuera del ámbito.
Cómo corregir infracciones
Para corregir una infracción de esta regla, llame a Dispose en el objeto antes de que todas las referencias a este estén fuera de ámbito.
Puede usar la instrucción using
(Using
en Visual Basic) para encapsular objetos que implementan IDisposable. Los objetos que se encapsulen de esta manera se eliminarán automáticamente al final del bloque using
. Sin embargo, las siguientes situaciones no deben o no se pueden controlar con una instrucción using
:
Para devolver un objeto descartable, el objeto debe construirse en un bloque
try/finally
fuera de un bloqueusing
.No inicialice los miembros de un objeto descartable en el constructor de una instrucción
using
.Cuando los constructores que están protegidos por un solo controlador de excepciones están anidados en la parte de adquisición de una instrucción
using
, un error en el constructor externo puede dar lugar a que el objeto creado por el constructor anidado no se cierre nunca. En el ejemplo siguiente, un error en el constructor StreamReader puede dar lugar a que el objeto FileStream no se cierre nunca. CA2000 marca una infracción de la regla en este caso.using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create))) { ... }
Los objetos dinámicos deben usar un objeto de propiedad reemplazada para implementar el patrón de eliminación de los objetos IDisposable.
Cuándo suprimir las advertencias
No suprima las advertencias de esta regla a menos que:
- Ha llamado a un método en el objeto que llama a
Dispose
, por ejemplo, Close. - El método que generó la advertencia devuelve un objeto IDisposable que encapsula el objeto.
- El método de asignación no tiene la propiedad de eliminación; es decir, la responsabilidad de desechar el objeto se transfiere a otro objeto o contenedor que se crea en el método y se devuelve al autor de la llamada.
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 CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000
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.CA2000.severity = none
Para obtener más información, consulte Procedimiento para suprimir advertencias de análisis de código.
Configuración del código para analizar
Use las opciones siguientes para configurar en qué partes del código base se va a ejecutar esta regla.
Puede configurar estas opciones solo para esta regla, para todas las reglas a las que se aplican o para todas las reglas de esta categoría (Confiabilidad) a las que se aplican. Para más información, vea Opciones de configuración de reglas de calidad de código.
Exclusión de símbolos específicos
Puede excluir símbolos específicos, como tipos y métodos, del análisis. Por ejemplo, para especificar que la regla no se debe ejecutar en ningún código dentro de los tipos con el nombre MyType
, agregue el siguiente par clave-valor a un archivo .editorconfig en el proyecto:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Formatos de nombre de símbolo permitidos en el valor de opción (separados por |
):
- Solo nombre de símbolo (incluye todos los símbolos con el nombre, con independencia del tipo contenedor o el espacio de nombres).
- Nombres completos en el formato de id. de documentación del símbolo. Cada nombre de símbolo necesita un prefijo de tipo símbolo, como
M:
para los métodos,T:
para los tipos yN:
para los espacios de nombres. .ctor
para los constructores y.cctor
para los constructores estáticos.
Ejemplos:
Valor de la opción | Resumen |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Coincide con todos los símbolos denominados MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Coincide con todos los símbolos denominados MyType1 o MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Coincide con un método MyMethod concreto con la signatura completa especificada. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Coincide con los métodos MyMethod1 y MyMethod2 concretos con las signaturas completas especificadas. |
Exclusión de tipos específicos y sus tipos derivados
Puede excluir tipos específicos y sus tipos derivados del análisis. Por ejemplo, para especificar que la regla no se debe ejecutar en ningún método dentro de los tipos con el nombre MyType
y sus tipos derivados, agregue el siguiente par clave-valor a un archivo .editorconfig en el proyecto:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Formatos de nombre de símbolo permitidos en el valor de opción (separados por |
):
- Solo nombre de tipo (incluye todos los tipos con el nombre, con independencia del tipo contenedor o el espacio de nombres).
- Nombres completos en el formato de identificador de documentación del símbolo, con un prefijo
T:
opcional.
Ejemplos:
Valor de la opción | Resumen |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Coincide con todos los tipos denominados MyType y todos sus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Coincide con todos los tipos denominados MyType1 o MyType2 , y todos sus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Coincide con un tipo MyType específico con el nombre completo dado y todos sus tipos derivados. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Coincide con los tipos MyType1 y MyType2 específicos con los correspondientes nombres completos y todos sus tipos derivados. |
Reglas relacionadas
Ejemplo 1
Si implementa un método que devuelve un objeto descartable, use un bloque try/finally sin un bloque catch para asegurarse de que el objeto se elimina. Al usar un bloque try/finally, permite la generación de excepciones en el momento del error y se asegura de que se elimine el objeto.
En el método OpenPort1, se puede producir un error en la llamada para abrir el elemento SerialPort del objeto ISerializable o en la llamada a SomeMethod. En esta implementación se desencadena una advertencia CA2000.
En el método OpenPort2, dos objetos SerialPort se declaran y establecen en NULL:
tempPort
, que se usa para probar la correcta realización de las operaciones del método.port
, que se usa para el valor devuelto del método.
tempPort
se construye y abre en un bloque try
y cualquier otro trabajo que sea necesario se realiza en el mismo bloque try
. Al final del bloque try
, el puerto abierto se asigna al objeto port
que se devolverá y el objeto tempPort
se establece en null
.
El bloque finally
comprueba el valor de tempPort
. Si no es NULL, se ha producido un error en una operación del método y tempPort
se cierra para garantizar la liberación de los recursos. El objeto Port devuelto contendrá el objeto SerialPort abierto si las operaciones del método se han realizado correctamente o será NULL si se produce un error en una operación.
public SerialPort OpenPort1(string portName)
{
SerialPort port = new SerialPort(portName);
port.Open(); //CA2000 fires because this might throw
SomeMethod(); //Other method operations can fail
return port;
}
public SerialPort OpenPort2(string portName)
{
SerialPort tempPort = null;
SerialPort port = null;
try
{
tempPort = new SerialPort(portName);
tempPort.Open();
SomeMethod();
//Add any other methods above this line
port = tempPort;
tempPort = null;
}
finally
{
if (tempPort != null)
{
tempPort.Close();
}
}
return port;
}
Public Function OpenPort1(ByVal PortName As String) As SerialPort
Dim port As New SerialPort(PortName)
port.Open() 'CA2000 fires because this might throw
SomeMethod() 'Other method operations can fail
Return port
End Function
Public Function OpenPort2(ByVal PortName As String) As SerialPort
Dim tempPort As SerialPort = Nothing
Dim port As SerialPort = Nothing
Try
tempPort = New SerialPort(PortName)
tempPort.Open()
SomeMethod()
'Add any other methods above this line
port = tempPort
tempPort = Nothing
Finally
If Not tempPort Is Nothing Then
tempPort.Close()
End If
End Try
Return port
End Function
Ejemplo 2
De forma predeterminada, el compilador de Visual Basic comprueba el desbordamiento en todos los operadores aritméticos. Por consiguiente, cualquier operación aritmética de Visual Basic puede producir una excepción de tipo OverflowException. Esto podría dar lugar a infracciones inesperadas de reglas como CA2000. Por ejemplo, la siguiente función CreateReader1 producirá una infracción de CA2000 porque el compilador de Visual Basic emite una instrucción de comprobación de desbordamiento para la suma que podría producir una excepción que provocaría que StreamReader no se eliminase.
Para corregir este problema, puede deshabilitar la emisión de comprobaciones de desbordamiento mediante el compilador de Visual Basic en el proyecto o puede modificar el código como en la siguiente función CreateReader2.
Para deshabilitar la emisión de comprobaciones de desbordamiento, haga clic con el botón secundario en el nombre del proyecto en el Explorador de soluciones y, a continuación, seleccione Propiedades. Seleccione Compilar>, en Opciones de compilación avanzadas y, a continuación, marque Quitar comprobaciones de desbordamiento con enteros.
Imports System.IO
Class CA2000
Public Function CreateReader1(ByVal x As Integer) As StreamReader
Dim local As New StreamReader("C:\Temp.txt")
x += 1
Return local
End Function
Public Function CreateReader2(ByVal x As Integer) As StreamReader
Dim local As StreamReader = Nothing
Dim localTemp As StreamReader = Nothing
Try
localTemp = New StreamReader("C:\Temp.txt")
x += 1
local = localTemp
localTemp = Nothing
Finally
If (Not (localTemp Is Nothing)) Then
localTemp.Dispose()
End If
End Try
Return local
End Function
End Class