C#Intermedio25 oct 2025

El 'finally' que se fue de vacaciones: Iteradores y la Disposición Olvidada

snippet.c#
using System;
using System.Collections.Generic;

public class Program
{
    public static IEnumerable<string> GetData()
    {
        try
        {
            yield return "FirstItem";
            Console.WriteLine("Inside try, after first yield.");
            yield return "SecondItem";
            Console.WriteLine("Inside try, after second yield.");
        }
        finally
        {
            Console.WriteLine("Finally block executed! Cleanup complete.");
        }
    }

    public static void Main(string[] args)
    {
        // Obtenemos el enumerador directamente, como un aventurero sin mapa.
        var enumerator = GetData().GetEnumerator();

        // Consumimos solo el primer elemento y luego nos vamos.
        if (enumerator.MoveNext())
        {
            Console.WriteLine($"Consumed: {enumerator.Current}");
        }

        // ¡Oops! Olvidamos cerrar la puerta o liberar los recursos.
        // ¿El 'finally' se ejecutó? ¡Averigüémoslo!
        Console.WriteLine("\nMain method finished. Did 'finally' run?");
    }
}

¿Qué crees que imprime?

Salida Esperada

Consumed: FirstItem
Finally block executed! Cleanup complete.

Main method finished. Did 'finally' run?

⚠️ Salida Real

Consumed: FirstItem

Main method finished. Did 'finally' run?

¿Por qué pasa esto?

¡Ah, el misterio de los iteradores y el `finally`! Pensarías que un bloque `finally` es como tu mamá 🤰: ¡siempre aparece para limpiar, pase lo que pase! Pero en el mundo de los iteradores (`yield return`), `finally` tiene sus propias reglas de juego. 🎮 Aquí la clave es la **disposición del enumerador**. Cuando usas `foreach`, C# es tu amable mayordomo y se asegura de llamar a `Dispose()` en el enumerador. Y es precisamente esa llamada a `Dispose()` la que activa el bloque `finally` del iterador. 🎉 Pero, ¿qué pasa si eres un *rebelde* y obtienes el enumerador manualmente (`GetData().GetEnumerator()`) y luego... ¡lo abandonas a su suerte! 😱 Si no lo consumes por completo o no llamas a `enumerator.Dispose()` explícitamente, el pobre `finally` se queda esperando, sin ejecutar su valiosa limpieza. Es como dejar la fiesta a medias y que la persona que puso la casa se quede con todo el desorden. 🧹 Por eso, nuestro `finally` nunca se ejecutó. ¡Recuerda siempre limpiar tus recursos! ♻️

Conceptos relacionados

iteratorsresource-managementIDisposable