Eficiência
A yield
palavra-chave cria efetivamente uma enumeração lenta sobre itens de coleção que podem ser muito mais eficientes. Por exemplo, se o foreach
loop iterar apenas os 5 primeiros itens de 1 milhão de itens, tudo será yield
retornado e você não acumulou uma coleção de 1 milhão de itens internamente primeiro. Da mesma forma, você desejará usar yield
com IEnumerable<T>
valores de retorno em seus próprios cenários de programação para obter as mesmas eficiências.
Exemplo de eficiência obtida em um determinado cenário
Não é um método iterador, uso potencialmente ineficiente de uma grande coleção
(a coleção intermediária é criada com muitos itens)
// 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.
Versão do iterador, eficiente
(nenhuma coleção intermediária é criada)
// 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.
Simplifique alguns cenários de programação
Em outro caso, facilita a programação de alguns tipos de classificação e mesclagem de listas, porque você apenas yield
retorna os itens na ordem desejada, em vez de ordená-los em uma coleção intermediária e trocá-los por lá. Existem muitos cenários desse tipo.
Apenas um exemplo é a mesclagem de duas 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;
}
Esse método retorna uma lista contígua de itens, efetivamente uma mesclagem sem nenhuma coleção intermediária necessária.
Mais informações
A yield
chave só pode ser utilizado em contexto de um método iteração (tendo um tipo de retorno IEnumerable
, IEnumerator
, IEnumerable<T>
, ou IEnumerator<T>
.) E existe uma relação especial com foreach
. Iteradores são métodos especiais. A documentação de produção e o iterador do MSDN contêm muitas informações e explicações interessantes dos conceitos. Certifique-se de correlacioná-lo com a foreach
palavra - chave lendo sobre isso também, para complementar sua compreensão dos iteradores.
Para aprender sobre como os iteradores alcançam sua eficiência, o segredo está no código IL gerado pelo compilador C #. A IL gerada para um método iterador difere drasticamente da gerada para um método regular (não iterador). Este artigo (O que a palavra-chave Rendimento realmente gera?) Fornece esse tipo de insight.