CA2000: Eliminar objetos antes de perder el ámbito
Nombre de tipo |
DisposeObjectsBeforeLosingScope |
Identificador de comprobación |
CA2000 |
Categoría |
Microsoft.Reliability |
Cambio problemático |
Poco problemático |
Causa
Se crea un objeto local de un tipo IDisposable pero el objeto no se elimina antes de que todas las referencias al objeto salgan de su ámbito.
Descripción de la regla
Si un objeto disponible no lo está explícitamente antes de que todas las referencias al objeto salgan de su ámbito, el objeto se eliminará en un momento indeterminado cuando el recolector de objetos no utilizados ejecute el finalizador del objeto. Dado que un evento excepcional podría evitar que el finalizador del objeto se ejecute, el objeto debería estar disponible en su lugar.
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 él estén fuera de su ámbito.
Observe que puede utilizar la instrucción using (Using en Visual Basic) para ajustar objetos que implementan IDisposable. Los objetos ajustados de esta manera se eliminan automáticamente al cerrar el bloque using.
Las situaciones siguientes son algunas situaciones donde la instrucción using no es suficiente para proteger objetos IDisposable y puede hacer que ocurra CA2000.
Devuelve un objeto descartable que requiere que el objeto se construya en un bloque try/finally fuera de un bloque using.
Inicializar miembros de un objeto descartable no debe realizarse en el constructor de una instrucción using.
Anidar constructores que sólo están protegidos por un controlador de excepciones. Por ejemplo,
using (StreamReader sr = new StreamReader(new FileStream("C:\myfile.txt", FileMode.Create))) { ... }
hace que ocurra CA2000 porque un error en la construcción del objeto StreamReader puede producir que el objeto FileStream nunca se cierre.
Los objetos dinámicos deberían usar un objeto de sombra para implementar el modelo Dispose de los objetos IDisposable.
Cuándo suprimir advertencias
No suprima una advertencia de esta regla a menos que haya llamado a un método del objeto que llame a Dispose, como Close.
Reglas relacionadas
CA2213: Aplique Dispose a los campos a los que se pueda
CA2202: No aplicar Dispose a los objetos varias veces
Ejemplo
Si implementa un método que devuelve un objeto descartable, utilice un bloque try/finally sin un bloque catch para asegurarse de la eliminación del objeto. Utilizando un bloque try/finally, permite que se produzcan excepciones en el punto 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 objeto ISerializable SerialPort o en la llamada a SomeMethod. Se provocó una advertencia CA2000 en esta implementación.
En el método OpenPort2, se declaran y establecen en NULL dos objetos SerialPort:
tempPort, que se usa para probar que las operaciones del método se realizan correctamente.
port, que se usa en el valor devuelto del método.
tempPort se construye y se abre en un bloque try y cualquier otro trabajo 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 asegurarse de que los recursos son liberados. El objeto de puerto devuelto contendrá el objeto SerialPort abierto si las operaciones del método son correctas, o será NULL si se produce un error en una operación.
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
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
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;
}
De forma predeterminada, el compilador de Visual Basic tiene toda la comprobación de los operadores aritméticos del desbordamiento. Por consiguiente, cualquier operación aritmética de Visual Basic podría producir una OverflowException. Esto podría llevar a infracciones inesperadas en reglas como CA2000. Por ejemplo, la siguiente función CreateReader1 generará una infracción CA2000 porque el compilador de Visual Basic está emitiendo una instrucción para la adición de comprobación de desbordamiento que podría producir una excepción que provocaría que StreamReader no se eliminase.
Para solucionar este problema, puede deshabilitar la emisión de las comprobaciones de desbordamiento mediante el compilador de Visual Basic en el proyecto o puede modificar su código como en la siguiente función de CreateReader2.
Para deshabilitar la emisión de las comprobaciones de desbordamiento, haga clic con el botón secundario en el nombre del proyecto en Explorador de soluciones y, a continuación, haga clic en Propiedades. Haga clic en Compilar, en Opciones de compilación avanzada y, a continuación, compruebe Quitar comprobaciones de desbordamiento con enteros.
Vea también
Referencia
Implementar Finalize y Dispose para limpiar recursos no administrados