Menu
Coddy logo textTech

IDisposable y la sentencia using

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 45 de 70.

Algunos objetos retienen recursos que el recolector de basura no puede limpiar automáticamente: identificadores de archivos, conexiones a bases de datos, sockets de red. La interfaz IDisposable proporciona una forma estándar de liberar estos recursos cuando hayas terminado de usarlos.

Una clase implementa IDisposable proporcionando un método Dispose():

public class FileHandler : IDisposable
{
    private bool disposed = false;
    
    public void Dispose()
    {
        if (!disposed)
        {
            Console.WriteLine("Releasing resources...");
            disposed = true;
        }
    }
}

Podrías llamar a Dispose() manualmente, pero ¿qué pasa si ocurre una excepción antes de llegar a esa línea? La sentencia using garantiza que la limpieza ocurra, incluso cuando las cosas salen mal:

using (FileHandler handler = new FileHandler())
{
    // Trabajar con el manejador
}  // Dispose() se llama automáticamente aquí

El C# moderno ofrece una sintaxis más limpia con la declaración using, que libera el objeto cuando sale del alcance:

void ProcessFile()
{
    using FileHandler handler = new FileHandler();
    // Trabajar con el manejador
}  // Se llama a Dispose() cuando el método finaliza

La sentencia using funciona con cualquier tipo que implemente IDisposable. Clases integradas como StreamReader, SqlConnection y HttpClient implementan esta interfaz, lo que hace que la gestión adecuada de recursos sea sencilla y fiable.

challenge icon

Desafío

Fácil

Vamos a construir un simulador de conexión a base de datos que demuestre la gestión adecuada de recursos utilizando la interfaz IDisposable y la sentencia using. Crearás una clase que rastree cuándo se abren y cierran las conexiones, asegurando que los recursos siempre se liberen correctamente.

Organizarás tu código en dos archivos:

  • DatabaseConnection.cs: Crea una clase DatabaseConnection en el espacio de nombres DataAccess que implemente IDisposable. Tu conexión debe:
    • Tener una propiedad ConnectionName (string, de solo lectura) establecida a través del constructor
    • Rastrear si la conexión ha sido eliminada (disposed) utilizando un campo booleano privado
    • Imprimir Connection opened: {ConnectionName} cuando se crea el objeto (en el constructor)
    • Implementar el método Dispose() para imprimir Connection closed: {ConnectionName}, pero solo si no ha sido eliminada previamente (evitar la doble eliminación)
    • Tener un método Query(string sql) que devuelva Executing on {ConnectionName}: {sql}
  • Program.cs: En tu archivo principal, demuestra la gestión adecuada de recursos utilizando la sentencia using con tu conexión de base de datos. Crea una conexión, ejecuta una consulta y deja que el bloque using maneje la limpieza automáticamente.

Recibirás dos entradas:

  • El nombre de la conexión (por ejemplo, MainDB)
  • La consulta SQL a ejecutar (por ejemplo, SELECT * FROM Users)

Usa una sentencia using para crear tu conexión. Dentro del bloque, llama al método Query e imprime su resultado. Cuando el bloque using termine, se llamará a Dispose() automáticamente.

Por ejemplo, si las entradas son MainDB y SELECT * FROM Users, la salida debería ser:

Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDB

Observa cómo la conexión se cierra automáticamente cuando termina el bloque using; nunca tienes que acordarte de llamar a Dispose() manualmente. ¡Este patrón asegura que los recursos siempre se limpien, incluso si ocurre una excepción dentro del bloque!

Pruébalo tú mismo

using System;
using DataAccess;

class Program
{
    public static void Main(string[] args)
    {
        string connectionName = Console.ReadLine();
        string sqlQuery = Console.ReadLine();
        
        // TODO: Usar una sentencia 'using' para crear una DatabaseConnection
        // Dentro del bloque using:
        // 1. Llamar al método Query con el sqlQuery
        // 2. Imprimir el resultado del método Query
        // El método Dispose se llamará automáticamente cuando termine el bloque using
        
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos