Semántica de la evaluación diferida
Comprenda la ejecución diferida de los iteradores.
Semántica de la evaluación diferida es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.
Ejecución diferida
Los iteradores y las consultas LINQ utilizan ejecución diferida: definir la consulta prácticamente no hace nada. El trabajo solo se realiza cuando enumera realmente el resultado, elemento por elemento.
Nada se ejecuta hasta enumerar
Al llamar a un método iterador no se ejecuta su cuerpo. El cuerpo comienza a ejecutarse solo cuando un foreach (u otro consumidor) solicita el primer valor.
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Numbers()
{
Console.WriteLine("-- iterator body started --");
yield return 1;
yield return 2;
}
public static void Main()
{
var seq = Numbers();
Console.WriteLine("query created, body not run yet");
foreach (var n in seq) Console.WriteLine(n);
}
}Los valores se producen uno a uno
Cada iteración ejecuta solo lo necesario del iterador para producir el siguiente valor. Este modelo basado en extracción mantiene bajo el consumo de memoria, incluso con secuencias enormes.
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Trace()
{
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("producing " + i);
yield return i;
}
}
public static void Main()
{
foreach (var n in Trace())
Console.WriteLine("consumed " + n);
}
}Volver a enumerar ejecuta de nuevo
Una secuencia diferida no tiene un resultado en caché. Enumerarla dos veces ejecuta el iterador dos veces, algo importante si el origen cambia o el trabajo es costoso.
using System;
using System.Collections.Generic;
public class Program
{
static int _calls = 0;
static IEnumerable<int> Counter()
{
_calls++;
yield return _calls;
}
public static void Main()
{
var seq = Counter();
foreach (var n in seq) Console.WriteLine(n);
foreach (var n in seq) Console.WriteLine(n);
Console.WriteLine("total runs: " + _calls);
}
}Capturar el estado actual
Como la ejecución es diferida, un iterador lee su origen en el momento de la enumeración, no cuando se define. Los cambios realizados después de definir la consulta son visibles.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var list = new List<int> { 1, 2 };
IEnumerable<int> doubled = Double(list);
list.Add(3); // added before enumeration
foreach (var n in doubled) Console.WriteLine(n);
}
static IEnumerable<int> Double(IEnumerable<int> nums)
{
foreach (var n in nums) yield return n * 2;
}
}Forzar la ejecución inmediata
Para obtener una instantánea de los resultados, materialice la secuencia con ToList() o ToArray(). Esto ejecuta el iterador una vez y almacena los valores, desvinculándolos de los cambios posteriores en el origen.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list = new List<int> { 1, 2 };
List<int> snapshot = Double(list).ToList(); // executed now
list.Add(99);
Console.WriteLine(string.Join(",", snapshot));
}
static IEnumerable<int> Double(IEnumerable<int> nums)
{
foreach (var n in nums) yield return n * 2;
}
}La evaluación en cortocircuito ahorra trabajo
Como los consumidores solicitan los valores de forma diferida, una operación como buscar la primera coincidencia puede detenerse antes de tiempo. El productor nunca calcula los valores que no se solicitan.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
static IEnumerable<int> Numbers()
{
for (int i = 1; ; i++)
{
Console.WriteLine("checking " + i);
yield return i;
}
}
public static void Main()
{
int firstBig = Numbers().First(n => n > 3);
Console.WriteLine("found " + firstBig);
}
}Excepciones diferidas
Una excepción dentro de un iterador no se produce cuando se llama al método, sino cuando la enumeración llega a la línea que falla. Esto puede sorprenderle si espera que la validación se realice de antemano.
using System;
using System.Collections.Generic;
public class Program
{
static IEnumerable<int> Risky(int divisor)
{
yield return 10 / divisor; // throws only during enumeration
}
public static void Main()
{
var seq = Risky(0);
Console.WriteLine("no error yet");
try { foreach (var n in seq) Console.WriteLine(n); }
catch (DivideByZeroException) { Console.WriteLine("caught during enumeration"); }
}
}Las canalizaciones diferidas se componen de forma eficiente
Encadenar operadores diferidos no hace que se ejecuten repetidamente. Cada valor atraviesa toda la canalización una sola vez, bajo demanda, lo que resulta eficiente y consume poca memoria.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var result = Enumerable.Range(1, 1000000)
.Where(n => n % 2 == 0)
.Select(n => n * n)
.Take(3);
foreach (var n in result) Console.WriteLine(n);
}
}Cuándo materializar
Materialice la secuencia cuando vaya a enumerarla varias veces, cuando el origen pueda cambiar o cuando deba capturar los resultados antes de liberar un recurso. En los demás casos, manténgala diferida para ahorrar memoria y trabajo.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var evens = Enumerable.Range(1, 10).Where(n => n % 2 == 0).ToList();
// Safe to enumerate many times now
Console.WriteLine("count: " + evens.Count);
Console.WriteLine("sum: " + evens.Sum());
}
}Pruébelo usted mismo
Observe directamente la ejecución diferida: se define una consulta, el origen cambia y los cambios aparecen en los resultados únicamente al enumerar.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var source = new List<int> { 1, 2, 3 };
var query = source.Where(n => n > 1); // not executed yet
source.Add(10);
source.Remove(2);
// Executes now, reflecting all changes
Console.WriteLine(string.Join(", ", query));
}
}Comprobación rápida
Razone sobre la ejecución diferida.
Resumen
La evaluación diferida (perezosa) ejecuta una secuencia únicamente cuando se enumera.
- Definir una consulta no realiza trabajo; consumirla sí.
- Volver a enumerarla ejecuta de nuevo el iterador.
- Los orígenes se leen al enumerar, por lo que los cambios posteriores son visibles.
- Las excepciones aparecen durante la enumeración.
- Use
ToList()/ToArray()para materializar cuando sea necesario.
Preguntas frecuentes
¿La lección «Semántica de la evaluación diferida» es gratis?
Sí — el texto completo de «Semántica de la evaluación diferida» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Semántica de la evaluación diferida»?
Comprenda la ejecución diferida de los iteradores. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar C# Academy?
No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Semántica de la evaluación diferida»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de C# Academy?
Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Métodos iteradores con yield return
- yield break y terminación anticipada
- Semántica de la evaluación diferida
- Enumerables personalizados