| Gustavo さんのプロフィールGustavo Bonanseaブログリスト | ヘルプ |
|
10月24日 Patrón DisposeHace unos días recibí un mail de Luigi desde Lima, Perú; preguntando sobre el uso del Patrón Dispose, dado que se enteró del seminario que estaba por dar; al cual no iba a poder asistir debido a las distancias. Para contestar a Luigi y para complementar lo que expuse en el seminario es que me tomo la libertad de escribir algunas líneas sobre el tema y les paso un link sobre el artículo que considero más completo sobre el tema (además de los del MSDN, por supuesto).
Patrón Dispose:
El CLR puede disponer enteramente de todos los objetos manejados, esto quiere decir que es su tarea crearlos y destruirlos; es el DIOS de los objetos manejados. El garbage collector puede disponer del espacio de memoria que ocupa el objeto cuando piense que nuestra aplicación no lo seguirá utilizando, puede mover el objeto de posición en caso de creerlo necesario (de hecho después de cada recolección se realiza una deframentación del montón que implica mover los objetos para que queden adyacentes), etc.
Pero, que pasa si utilizamos un recurso que se encuentra fue de los límites del CLR. Supongamos que nos queremos conectar remotamente con algún dispositivo especial y las librerías para conectarse con el mismo se encuentran publicadas en una dll que no es .Net. ¿Cómo podemos asegurarnos de que se liberará el recurso una vez que no se necesite más? El CLR no puede hacerlo automáticamente dado que no tiene conocimiento sobre qué métodos tiene la dll y para qué sirve cada uno; por lo tanto no podrá cerrarlo por sí mismo. Para paliar esta situación podemos utilizar el Patrón Dispose. Este patrón define una función especial llamada Dispose que sirve para que el usuario (entiéndase por "usuario" a cualquier objeto que utilice la clase, no a una persona física que ejecute el programa) la llame explícitamente para liberar los recursos no manejados (en este ejemplo la conexión con el dispositivo), por lo tanto en el cuerpo de este método (Dispose) deberemos hacer una llamada a la función no manejada que libera los recursos del dispositivo. Quiero aclarar en este punto que no basta con que el usuario de la clase que contiene el recurso no manejado haga nulo el objeto, eso solo libera (lo deja en manos del Garbage Collector en realidad) la parte manejada del mismo, pero no llama al método necesario para liberar el recurso no manejado, es decir que no se llama al método de la dll que lo cierra, por eso debe llamar explícitamente al método Dispose.
En el escenario ideal el usuario de la clase llamará al método Dispose inmediatamente después de haber terminado de usarla, liberando así el recurso para que sea utilizado por otro objeto. ¿Qué pasa si el programador olvida llamar al método Dispose? Desgraciadamente la respuesta es que el recurso no se liberará. Por ello el patrón Dispose incluye una implementación del método Finalize. Éste método tiene la característica especial de que se llama automáticamente por el CLR antes de que el objeto sea destruido, por lo tanto aunque el programador olvide llamar explícitamente al Dispose éste se llamará automáticamente cuando el objeto sea destruido por el Garbage Collector. Cabe aclarar que éste es un mecanismo de emergencia, el programador DEBE llamar explícitamente al método Dispose, solo en caso de una omisión debe dejarse en manos del finalizador esta tarea. ¿Por qué? Porque no tenemos control de cuando se llamará el método Finalize, ésto depende de que se ejecute el Garbage Collector y éste le informe al thread de finalización que debe llamar al método. Si los requerimientos de memoria de la aplicación a partir del momento en que se deja de utilizar el objeto no le aplican demasiada presión el GC no correrá y la conexión con el dispositivo puede pasar mucho tiempo si cerrarse (en el caso extremo puede ser hasta que se termine el programa).
Quiero aclarar que el uso del método Dispose solo debe utilizarse para el caso de necesitar la liberación de un recurso no manejado y los usuarios de la clase que implementan el método deben llamarlo en forma explícita, el finalizador debe incluirse en esa clase como medida preventiva en caso de la omisión de la llamada al Dispose por parte del código que utiliza la clase.
Ejemplo (extraído del documento de Joe Duffy que se referencia debajo. Es un poco más completo que el de mi seminario)
public class ComplexCleanupBase : IDisposable {
// some fields that require cleanup private bool disposed = false; // to detect redundant calls
public ComplexCleanupBase() { // allocate resources
protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // dispose-only, i.e. non-finalizable logic }
// shared cleanup logic disposed = true; } }
~ComplexCleanupBase() { Dispose(false); }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
}
Algunas consideraciones sobre el ejemplo:
Espero que haya sido de ayuda.
Mas información: Joe Duffy: Dispose, Finalization, and Resource Management
コメント (10 件)
トラックバックこの記事のトラックバックの URL は次のとおりです。 http://misopiniones.spaces.live.com/blog/cns!2737DC89A4AAB26B!476.trak この記事を参照しているブログ
|
|
|