Compartir a través de


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

IDisposable

Implementar Finalize y Dispose para limpiar recursos no administrados