Eficiencia
La yield
palabra clave crea efectivamente una enumeración perezosa sobre los elementos de la colección que puede ser mucho más eficiente. Por ejemplo, si su foreach
ciclo itera solo sobre los primeros 5 elementos de 1 millón de elementos, eso es todo lo que yield
devuelve, y no acumuló una colección de 1 millón de elementos internamente primero. Del mismo modo que se quiere utilizar yield
con IEnumerable<T>
valores de retorno en sus propios escenarios de programación para lograr la misma eficiencia.
Ejemplo de eficiencia obtenida en un escenario determinado
No es un método iterador, uso potencial ineficiente de una gran colección
(la colección intermedia se construye con muchos elementos)
// Method returns all million items before anything can loop over them.
List<object> GetAllItems() {
List<object> millionCustomers;
database.LoadMillionCustomerRecords(millionCustomers);
return millionCustomers;
}
// MAIN example ---------------------
// Caller code sample:
int num = 0;
foreach(var itm in GetAllItems()) {
num++;
if (num == 5)
break;
}
// Note: One million items returned, but only 5 used.
Versión de iterador, eficiente
(no se crea una colección intermedia)
// Yields items one at a time as the caller's foreach loop requests them
IEnumerable<object> IterateOverItems() {
for (int i; i < database.Customers.Count(); ++i)
yield return database.Customers[i];
}
// MAIN example ---------------------
// Caller code sample:
int num = 0;
foreach(var itm in IterateOverItems()) {
num++;
if (num == 5)
break;
}
// Note: Only 5 items were yielded and used out of the million.
Simplifica algunos escenarios de programación
En otro caso, hace que algunos tipos de clasificación y fusión de listas sean más fáciles de programar porque simplemente yield
vuelve a colocar los elementos en el orden deseado en lugar de ordenarlos en una colección intermedia e intercambiarlos allí. Hay muchos escenarios de este tipo.
Un solo ejemplo es la fusión de dos listas:
IEnumerable<object> EfficientMerge(List<object> list1, List<object> list2) {
foreach(var o in list1)
yield return o;
foreach(var o in list2)
yield return o;
}
Este método devuelve una lista contigua de elementos, efectivamente una fusión sin necesidad de una colección intermedia.
Más información
La yield
palabra clave sólo se puede utilizar en el contexto de un método iterador (que tiene un tipo de retorno de IEnumerable
, IEnumerator
, IEnumerable<T>
, o IEnumerator<T>
.) Y hay una relación especial con foreach
. Los iteradores son métodos especiales. La documentación de rendimiento de MSDN y la documentación del iterador contienen mucha información interesante y explicaciones de los conceptos. Asegúrese de correlacionarlo con la foreach
palabra clave al leerlo también, para complementar su comprensión de los iteradores.
Para conocer cómo los iteradores logran su eficiencia, el secreto está en el código IL generado por el compilador de C #. La IL generada para un método iterador difiere drásticamente de la generada para un método regular (no iterador). Este artículo (¿Qué genera realmente la palabra clave Yield?) Proporciona ese tipo de información.