1. Funciones implementadas por yield
Rendimiento de la cosecha:
Veamos el siguiente código, que implementa una función similar a recorrer un array con foreach a yield return, indicando que yield return también se usa para implementar la función del iterador.
Corte de Flujo:
Mirando el código de abajo, solo se producen 1 y 2, pero no 3, lo que indica que el iterador fue detenido por yield break, por lo que yield break se usa para terminar la iteración.
2. Solo puede usarse en <T><T>métodos, operadores, accesorios que deben devolver un IEnumerable, IEnumerable, IEnumerator o IEnumerator.
3. El principio de implementación de la palabra clave yield
Sustituimos el bucle foreach por un bucle while y descubrimos que, aunque no implementamos GetEnumerator(), ni las propiedades MoveNext() y Current correspondientes de IEnumerator, seguimos trabajando con estas funciones.
En cuanto a por qué ocurre esto, podemos usar ILSpy para descompilar el exe generado y encontrar la razón.
Ya que la descompilación directa a C# será como está
Por ello, decidimos descompilarlo en código IL con anotaciones en C#, aunque la legibilidad es pobre, pero podemos entender los principios en detalle. Primero veamos la traducción del programa, una nueva clase se genera automáticamente durante la compilación.
Echemos un vistazo más detallado al código, y EnumerableFuc() devuelve esta nueva clase.
Al observar la implementación de la clase que este código genera automáticamente, podemos ver que hereda IEnumerable<T>, IEnumerable, IEnumerator o IEnumerator, y <T>deberíamos poder suponer que esta nueva clase es la razón por la que no implementamos las propiedades MoveNext() y Current correspondientes de IEnumerator, pero aún podemos usar estas funciones con normalidad.
Veamos cómo se itera esta clase, principalmente veamos la función MoveNext()
Cada llamada a la función MoveNext() añade 1 al estado, y se realizan un total de 4 iteraciones, las tres primeras devolviendo true y la última false, lo que significa el final de la iteración. Estas cuatro iteraciones corresponden a las sentencias en enumberableFuc() que se dividen en 4 partes por 3 sentencias yield return.
El proceso real de iterar con enumberableFuc() es:
1. Ejecuta la función enumberableFuc() para obtener una instancia de la clase generada automáticamente por el código. 2. Luego llama a la función GetEnumberator() para empezar a iterar sobre la clase adquirida como iterador. 3. Cada vez que ejecutas MoveNext(), el estado aumenta en 1, y la instrucción switch te permite ejecutar diferentes partes del código cada vez que llamas a MoveNext(). 4。 MoveNext() devuelve false, terminando. Esto también muestra que la palabra clave yield es en realidad un azúcar sintáctico, y que en última instancia es una función iterativa implementada implementando <T>interfaces IEnumberable, IEnumberable, <T>IEnumberator e IEnumberator.
|