Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
43m 58s
Cuando se encuentra por primera vez la palabra clave yield en C#, puede parecer desconcertante. ¿Cómo funciona exactamente? ¿Cuándo se debe utilizar yield return en lugar de una sentencia return tradicional? Para conseguir una comprensión completa, vamos a recorrer una explicación detallada basada en el excelente tutorial de Tim Corey en YouTube: "Intro to Yield in C# - What it is, how to use it, and when it is useful"
En esta guía, haremos referencia a puntos específicos del vídeo de Tim por marca de tiempo para facilitar la navegación e incluiremos ejemplos prácticos para mostrar cómo yield transforma la forma en que se manejan los flujos de datos, las grandes colecciones y la evaluación perezosa.
Tim comienza presentando la palabra clave yield y destacando que a menudo puede resultar confusa para los desarrolladores que se encuentran con ella por primera vez. Explica que la sentencia yield permite a un método detener la ejecución, mantener su estado y continuar desde donde lo dejó en la siguiente llamada. Tim subraya que entender el rendimiento es fundamental para procesar datos de forma eficiente, sobre todo cuando se trata de grandes conjuntos de datos o se implementa una lógica de iteración personalizada.
Para eliminar distracciones, Tim crea una sencilla aplicación de consola en Visual Studio, llamada "YieldDemoApp"

A continuación, Tim profundiza en la teoría. En el minuto 2:04, describe el comportamiento de yield: En lugar de procesar toda una colección a la vez, la sentencia yield retiene un punto -como meter un pulgar en un libro- para que la ejecución pueda pausarse y reanudarse más tarde.
Este comportamiento es crucial para la ejecución diferida, en la que los valores se generan solo cuando se necesitan, en lugar de precomputar todo por adelantado. La descripción de Tim sienta claramente las bases para comprender cómo funciona el retorno de rendimiento.
En el método estático void Main de la clase Program, establece mensajes básicos como "Inicio de la aplicación" y "Fin de la aplicación" utilizando Console.WriteLine, lo que ayuda a visualizar el flujo claramente cuando se trabaja con un bucle foreach más adelante.
Este ejemplo de código inicial se centra únicamente en la implementación del rendimiento, sin incluir complejidades de interfaz de usuario.
Para demostrarlo, Tim crea una clase PersonModel con las propiedades FirstName y LastName y un constructor. Cuando se crea un objeto PersonModel, se imprime un mensaje que indica qué usuario se ha inicializado. Esto ayuda a visualizar cuándo se crean los objetos y cuándo se consumen.

Este sencillo paso de generación de código prepara el terreno para trabajar con iteradores personalizados.
En el minuto 5:06, Tim pasa a una clase DataAccess con un método GetPeople que devuelve IEnumerable<PersonModel>. Inicialmente, el valor de retorno es una lista poblada con tres instancias PersonModel: Tim Corey, Sue Storm y Jane Smith.

Este método iterador carga todos los objetos inmediatamente en memoria antes de que comience la iteración - un punto importante que Tim contrasta más adelante con el uso de yield.

Después de ejecutar el bucle foreach, Tim muestra que los tres usuarios se crean antes incluso de que se lea el primer elemento. Esto pone de relieve un problema potencial cuando se trabaja con grandes colecciones o grandes conjuntos de datos: el elevado uso de memoria.

Tim explica que si tuviéramos, digamos, mil usuarios, habríamos creado mil objetos aunque solo necesitáramos unos pocos, lo que daría lugar a una asignación ineficiente de memoria.
En el minuto 10:01, Tim modifica GetPeople para utilizar yield return en lugar de crear una colección temporal (una List). Cada sentencia yield return emite directamente un PersonModel cada vez.
Este código crítico dentro del método permite la evaluación perezosa, donde el siguiente elemento se genera sólo cuando es necesario por el foreach.
Tim también aclara que el tipo de retorno del método debe ser IEnumerable<PersonModel>, y que el uso de List anularía el propósito de la ejecución diferida.
Tim utiliza puntos de interrupción para explicar el proceso paso a paso. Muestra que antes de la primera llamada a MoveNext, la secuencia está vacía. Sólo cuando foreach necesita el siguiente valor, el compilador activa el bloque iterador y ejecuta la línea yield return num, que inicializa y devuelve el PersonModel.

Tim destaca que el compilador genera máquinas de estado especiales bajo el capó para gestionar la ejecución pausada y reanudada.
Tim explica por qué el rendimiento es tan eficaz:
Puede buscar un registro cada vez.
Puede limitar el número de int que necesita.
Se evita cargar toda la colección en la memoria.
Se mejora la escalabilidad, especialmente cuando se trabaja con procesamiento de archivos o flujos de datos de gran tamaño.
Mediante el uso de .Take(2) de LINQ, Tim demuestra cómo sólo se inicializan dos objetos a pesar de que existen tres declaraciones de retorno de rendimiento, lo que pone de relieve la ejecución diferida en acción.
Tim crea un nuevo método estático IEnumerable<int> GetPrimeNumbers() dentro de una clase Generators. En este bucle infinito, Tim utiliza una función auxiliar IsPrimeNumber(int number) para comprobar la primalidad. Si el número es primo, utiliza yield return number para emitirlo.
Este ejemplo muestra que el rendimiento es fundamental para manejar secuencias infinitas con seguridad.
Sin rendimiento, el código se bloquearía debido al consumo ilimitado de memoria. Sin embargo, al utilizar yield, la ejecución diferida garantiza que los números se generen bajo demanda.
A continuación, Tim muestra cómo obtener de forma segura sólo un número fijo de números primos:
var primeNumbers = Generators.GetPrimeNumbers().Take(10000);Dim primeNumbers = Generators.GetPrimeNumbers().Take(10000)Este código escrito dentro del void estático Main obtiene eficientemente sólo 10.000 primos.
Dado que el retorno de rendimiento produce números uno a uno, el uso de memoria se mantiene bajo.
Tim va más allá y explica cómo controlar la iteración manualmente.
Crea un var iterator = primeNumbers.GetEnumerator(), luego utiliza un bucle for con int i y llama a iterator.MoveNext() para obtener elementos manualmente.
Este enfoque manual permite una iteración personalizada, preguntando por el siguiente valor sólo cuando sea necesario y mostrando que el método se reanuda exactamente desde donde se detuvo por última vez.
En el minuto 36:45, Tim advierte: convertir una secuencia yield en una lista con .ToList() provoca una evaluación completa inmediata.
Si llamas a .ToList() en una secuencia infinita, corres el riesgo de que tu aplicación se bloquee.
Tim subraya que el retorno de rendimiento está pensado para la evaluación perezosa, y que llamar a .ToList() rompe este patrón al forzar la materialización completa en memoria.
Al trabajar con métodos LINQ, Tim recomienda ser cauteloso a la hora de introducir .ToList().
Tim concluye insistiendo en que, si bien la palabra clave yield añade una ligera sobrecarga (al mantener una máquina de estados), las ventajas de un menor uso de memoria y de la evaluación perezosa la convierten en una potente herramienta de trabajo:
Grandes conjuntos de datos
Archivos de gran tamaño
Iteradores personalizados
Secuencias infinitas
Flujos de datos
Tratamiento diferido
Sugiere practicar con el rendimiento en diferentes proyectos para desarrollar una comprensión más profunda del rendimiento y evitar errores comunes.
Tim concluye invitando a los espectadores a compartir cómo han utilizado el rendimiento en el código de producción.
Al recorrer el vídeo de Tim Corey, hemos visto las inmensas ventajas que la palabra clave yield aporta a C#. Desde la creación de iteradores personalizados hasta la gestión eficiente de grandes colecciones, yield return permite que los retornos de función sean más inteligentes y eficientes en términos de memoria. Tanto si trabaja con var number, var point, var reader, var connection o grandes conjuntos de datos, el dominio de yield puede elevar drásticamente sus habilidades de codificación en C#.
Si no has explorado antes el uso de yield, ahora es el momento perfecto para practicarlo a través de ejemplos sencillos y comprender mejor cómo funciona el retorno yield dentro del compilador de C#. Echa un vistazo al canal oficial de Tim YouTube Channel para ver más vídeos interesantes.
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy