Patrón dispose

26·Feb·2015

|

Actualmente, es común estar en una situación dentro de un proyecto donde estamos trabajando con varios recursos utilizando memoria. Existen recursos manejables y no manejables por la máquina virtual de .Net (Common Language Runtime CLR). Después del uso de estos recursos hay que liberar la memoria ocupada por estos objetos. El no hacerlo puede conllevar a problemas de memoria (conocidos como Memory Leaks). Cuando un objeto manejable por el CLR ya no está en uso el Garbage Collector libera automáticamente la memoria asignada al objeto, pero no podemos asegurar cuando va a realizar esta liberación de memoria. Los recursos no manejables, como las conexiones a una Base de Datos o archivos deben ser liberados de forma manual.

Gestionando de manera manual la liberación de memoria

Podemos hacer que nuestros objetos implementen la interfaz IDisposable para una correcta liberación de memoria, con el objetivo de que no haya riesgo de que cualquier usuario del objeto acceda a un recurso que haya sido liberado previamente. De esta manera evitamos que se lance la excepción ObjectDisposedException.
Es recomendable llamar al método Dispose en el lugar adecuado; es decir, en el momento donde debe liberarse los recursos y sabiendo que no se van a consumir.
A continuación vamos a ver cómo podemos implementar en nuestro código la liberación de memoria de forma manual.

Con bloques Try-Finally

Esta es la forma básica de consumir recursos antes de que el bloque using fuese implementado en el framework .Net. La manera correcta de consumir un recurso es garantizar el éxito de que lo esté utilizando. Aun así, sabemos que múltiples errores pueden surgir a la hora de consumirlo. Por este motivo se justifica el uso de un bloque try. Por otro lado, el bloque finally se ejecuta siempre, por lo tanto es una zona segura donde realizar la limpieza manual de memoria.

Veamos un ejemplo:

alt text

Con bloques Using

La diferencia esencial entre el bloque using y el bloque try-finally reside en que el bloque using realiza una llamada implícita al método Dispose al final de su ámbito de actuación. Es necesario que la clase que utiliza using implemente la interfaz IDisposable. Es recomendable utilizar using ya que viene como característica del framework y elimina la necesidad de realizar una gestión manual de limpieza de memoria. El compilador genera automáticamente bloque try-finally a partir del bloque using.

Veamos un ejemplo:

alt text

La mayoría de las clases del framework .Net como StreamReader, StreamWriter, DataTable, entre muchas otras, implementan la interfaz IDisposable. En el ejemplo anterior, se llama al método Dispose de TextReader justo al salir del bloque using.

Con Finalizadores

Los métodos finalizadores son llamados al final del ciclo de exploración que realiza el GarbageCollector. Llevan a cabo la limpieza de recursos no manejados. Es una alternativa cuando el objeto que consume el recurso no llama al método Dispose. No es necesario implementar un finalizador si se llama al método Dispose en un bloque try-finally o usuando un bloque using.

Implementando el Patrón Dispose

  1. En primer lugar creamos una clase que implemente la interfaz IDisposable.
  2. Creamos un flag que controle si el objeto ha sido liberado o no. (bool disposed)
  3. Creamos un método Dispose que reciba como parámetro un bool que, en función del valor, nos indique si se quiere liberar los recursos gestionados o no. Este método debe ser protected y virtual. Si se quiere tener clases derivadas de este objeto que van a necesitar liberar recursos, la subclase debe sobreescribir este método. Se le asigna protected para limitar la visibilidad del método a otras clases fuera de la jerarquía. La clase base (si existe) no debe tener ningún finalizador.
  4. Creamos un método Dispose sin parámetros. Dentro de este método llamaremos al método Dispose(true), donde se realiza la liberación de memoria, y realizaremos una llamada al método SuppressFinalize del GarbageCollector para indicarle que no llame al finalizador del objeto.
  5. Finalmente, implementamos un finalizador si no se tiene intención de utilizar el objeto dentro de un bloque try-catch o using.

Veamos un ejemplo:

alt text

Para más información sobre IDisposable podéis consultar el siguiente link de MSDN

Más información

Contacta con raona