DE .NET, SQLSERVER Y MÁS, APRENDE CONMIGO!✔

Desarrollo de todo tipo de aplicaciones y Administración de Base de datos con Tecnología Microsoft


UNETE

La interfaz IDisposable

0

 

La interfaz IDisposable 

La interfaz IDisposable nos provee de la forma de crear clases desechables, que pueden ser desechadas de forma casi determinística. El método Dispose que implementa no es un destructor, de hecho, no deja de ser un simple método cualquiera con la particularidad de que su misión contractual (por el hecho de pertenecer a IDisposable) es liberar los recursos administrados y no administrados. Una vez implementada, podríamos “desechar” nuestra clase invocando al método .Dispose ó usando nuestra clase dentro de una sentencia using.

A bote pronto parece sencillo pero aparecen varias casuísticas especiales, de las cuales las más destacables son:

  1. ¿Qué sucede si se llama a Dispose mientras ya se esta ejecutando otro Dispose? Pués es fácil de predecir, si se intenta hacer un Stream.Close() de un Stream que ya ha sido destruido… se dispararía una NullReferenceException.
  2. ¿Qué sucede si se nos olvida hacer un Dispose? Pues también es obvio, a no ser que tengamos definido un destructor que también libere los recursos… cuando el GC recolecte esta clase… quedarán sin liberar.
  3. ¿Qué sucede si tenemos Dispose y un destructor con el mismo código duplicado para liberar recursos? Pues que si llamamos a Dispose, después cuando el GC detecte que hay un destructor y lo llame, si no hay forma de averiguar si los recursos se han liberado ó no… podría ó podrían dispararse NullReferenceException al intentar liberar recursos ya liberados. Además del problema intrínseco de diseño que implica tener código duplicado.
  4. ¿Y si apuntan a un código en común para liberar recursos? Pues volviendo a la casuística #3, si no tenemos forma de controlar si se ha liberado ya podríamos obtener el mismo resultado.
  5. ¿Y si pudiese controlar cuando han sido liberados? Pues el único defecto que quedaría es el hecho de que el GC encolaría la clase al recolectarla por el mero hecho de tener un destructor definido, siendo esto no un problema, pero si mejorable.

Estos cinco casos quedan cubiertos con la correcta implementación del patrón desechable:

    class MiClase : IDisposable

    {

        private bool disposing;

 

        //

        // … resto del código …

        //

 

        /// <summary>

        /// Método de IDisposable para desechar la clase.

        /// </summary>

        public void Dispose()

        {

            // Llamo al método que contiene la lógica

            // para liberar los recursos de esta clase.

            Dispose(true);

        }

 

        /// <summary>

        /// Método sobrecargado de Dispose que será el que

        /// libera los recursos, controla que solo se ejecute

        /// dicha lógica una vez y evita que el GC tenga que

        /// llamar al destructor de clase.

        /// </summary>

        /// <param name=”b”></param>

        protected virtual void Dispose(bool b)

        {

            // Si no se esta destruyendo ya…

            if (!disposing)

            {

                // La marco como desechada ó desechandose,

                // de forma que no se puede ejecutar este código

                // dos veces.

                disposing = true;

 

                // Indico al GC que no llame al destructor

                // de esta clase al recolectarla.

                GC.SuppressFinalize(this);

 

                // … libero los recursos…

            }

        }

 

        /// <summary>

        /// Destructor de clase.

        /// En caso de que se nos olvide “desechar” la clase,

        /// el GC llamará al destructor, que tambén ejecuta la lógica

        /// anterior para liberar los recursos.

        /// </summary>

        ~MiClase()

        {

            // Llamo al método que contiene la lógica

            // para liberar los recursos de esta clase.

            Dispose(true);

        }

    }

 

·         La variable booleana ‘disposing’ controla si se ha desechado ó se esta desechando el objeto para que no se ejecute dos veces.

·         El método ‘Dispose(bool b)’ es realmente quien libera los recursos, primero comprueba que la instancia no ha sido desechada ó este desechandose, libera los recursos y ejecuta ‘GC.SuppressFinalize(this)’ para que se suprima el constructor de esta clase y el GC pueda recolectarla sin más. De esta forma solo se ejecutaría este método una vez por instancia.

·         El método ‘Dispose()’ llama a su homónimo sobrecargado ‘Dispose(bool b)’ para que deseche la instancia. El destructor de clase también llama a ‘Dispose(bool b)’ para que deseche la instancia. De esta forma, tanto si desechamos el objeto intencionadamente, como si se nos olvida y lo destruye el GC, se ejecutará el mismo método y solo una vez por instancia.

 

DEMOSTRACIÓN

En Visual Studio vamos a dar click en menú File à New à Project


En la Ventana emergente le damos click a Window, seleccionamos la opción “Console Application” y espacio Name colocamos el nombre del proyecto que para el Ejemplo es “Demo 11 20483” y luego presionamos el botón OK


En el editor de código, debajo del método Main() crearemos la clase ‘textfile1’ que implementa la interfaz IDisposable.



En el método Main() codificaremos lo siguiente:


La salida de la consola sería la siguiente:



Tal vez te interesen estas entradas

No hay comentarios