Por lo tanto, esta cuestión se acaba de preguntar sobre SO:¿Puede alguien explicar este código de evaluación perezosa?
How to handle an "infinite" IEnumerable?
Mi código de ejemplo:
public static void Main(string[] args)
{
foreach (var item in Numbers().Take(10))
Console.WriteLine(item);
Console.ReadKey();
}
public static IEnumerable<int> Numbers()
{
int x = 0;
while (true)
yield return x++;
}
Por favor alguien puede explicar por qué esto es perezoso evaluar? He buscado este código en Reflector, y estoy más confundido que cuando comencé.
salidas Reflector:
public static IEnumerable<int> Numbers()
{
return new <Numbers>d__0(-2);
}
Para el método de números, y se ve que han generado un nuevo tipo para que la expresión:
[DebuggerHidden]
public <Numbers>d__0(int <>1__state)
{
this.<>1__state = <>1__state;
this.<>l__initialThreadId = Thread.CurrentThread.ManagedThreadId;
}
Esto no tiene sentido para mí. Hubiera supuesto que era un ciclo infinito hasta que reuní ese código y lo ejecuté yo mismo.
EDITAR: Así que entiendo ahora que .Tomar() puede decirle al foreach que la enumeración ha 'terminado', cuando en realidad no tiene, pero no debe Números() se llama en su totalidad antes de encadenamiento reenviar al Take()? El resultado de Take es lo que en realidad se está enumerando, ¿correcto? ¿Pero cómo se está ejecutando Take cuando Numbers no ha evaluado completamente?
EDIT2: Entonces, ¿se trata de un truco de compilación específico impuesto por la palabra clave 'yield'?
Sí, pero ¿no se debería evaluar por completo a Numbers() para continuar con la llamada de Take? Entiendo que Numbers en sí es un ciclo infinito. ¿Por qué la adición de .Take() detiene repentinamente la evaluación de Numbers en su totalidad? – Tejs
Interesante. Gracias por el enlace! Esa pregunta (y el código) me hizo dar una doble vuelta, ¡y ahora me doy cuenta de que tengo más que aprender sobre los Enumerables! – Tejs