Talvez você nunca tenha ouvido falar desta palavra – pelo menos no C#, pois ela também está presente no mercado financeiro – , mas acredite, ela está presente no hall de palavras reservadas do C# desde a versão 2.0. Mas para que ela serve? O uso do Yield faz com que o compilador gere um Enumerable no momento do retorno, assim sendo, poderá ser utilizada de duas formas:
- yield return <expressão> ou,
- yield break.
Uma iteração feita através do yield, faz com que o método que retorna o valor devolva o controle para o método que fez a chamada, este por sua vez executa alguma ação na iteração atual e ao iterar novamente no método anterior (iteração com yield), este continua exatamente de onde parou, como se fosse uma máquina de estado, armazenando sempre o estado anterior da ação, neste caso, o ponto correto de onde a iteração devolveu o controle.
Quando usar?
A utilização do yield se encaixa perfeitamente e dois cenários, iterações customizadas – onde desejamos filtrar alguns dados de uma coleção – e iterações onde precisamos manter o valor anterior de um resultado para uma utilização posterior – Stateful.
Filtrando valores com yield
No código abaixo temos uma iteração sobre um IEnumerable retornado pelo método GetCustomValues.
foreach (var number in GetCustomValues())
{
System.Console.WriteLine(number);
}
O método GetCustomValues itera sobre uma sequência numérica onde seleciona apenas os valores maiores que 5 em um total de 10. Essa seleção é adicionada em uma nova lista chamada myList que armazena os valores selecionados e ao final devolve o resultado, um exemplo bem simples, mas também comum em muitas de nossas tarefas.
static IEnumerable<int> GetCustomValues()
{
List<int> myList = new List<int>();
for (int i = 0; i < 10; i++)
{
if (i > 5)
myList.Add(i);
}
return myList;
}
Faremos algumas modificações no método GetCustomValues para fazer a utilização do yield.
static IEnumerable<int> GetCustomValues()
{
for (int i = 0; i < 10; i++)
if (i > 5)
yield return i;
}
Quando a condição for atingida, ( i > 5), o método devolverá o controle para o método “chamador” no caso a iteração com foreach, onde será exibido o valor, em seguida o controle será devolvido para o método GetCustomValues, onde este continuará de onde parou e retornará o próximo valor. Essa alternância de controles continuará até que o último valor seja atingido.
Portanto temos um código mais enxuto e que utiliza menos memória, pois não há uma instância (myList) sendo preenchida com os valores desejados, estes agora são retornados diretamente à quem os chamou.
Mantendo o estado de uma iteração
Este segundo cenário de utilização do yield, mostrará como podemos iterar em uma sequência numérica e obter um valor sempre a partir do valor anterior. Isso é possível porque como já comentado, o yield funciona como uma máquina de estado mantendo sempre o estado da última operação realizada.
Um exemplo prático dessa característica do yield está na própria documentação da Microsoft, é a função Power.
class Program
{
static void Main(string[] args)
{
foreach (var value in Power(2, 4))
{
System.Console.WriteLine(value);
}
Console.ReadKey();
}
static IEnumerable<int> Power(int number, int exponent)
{
int result = 1;
for (int i = 1; i <= exponent; i++)
{
yield return result *= number;
}
}
}
A mágica ocorre na variável result, após esta ter sido iniciada com o valor 1, ela passa a receber o resultado na linha 18, onde há o retorno. Na próxima vez que que a função for chamada, o conteúdo da variável result não será mais 1, será o último total armazenado, e assim seguirá até o fim da iteração.
Na sequência de imagens abaixo, ficará mais fácil compreender.
A imagem abaixo mostra o início da primeira iteração, onde a variável result é iniciada com o valor 1 e na linha de retorno já recebe um valor.

Na sequência, podemos ver o início da segunda iteração onde a variável mantém o último valor, apenas lembrando que entre cada iteração, o controle é devolvido para outro método (yield return) e volta em seguida.

Uma nova iteração em andamento, sempre armazenando o valor anterior.

Preparei também uma versão não recursiva da famosa sequência de Fibonacci utilizando o yield.
static IEnumerable<int> Fibonacci(int size)
{
int current = -1, fib = 0, next = 1;
for (int i = 1; i <= size; i++)
{
fib = current + next;
current = next;
next = fib;
yield return fib;
}
}
Como qualquer coisa em computação, sempre há os cenários ideais e aqueles nem tanto – propósitos de cada ferramenta – . Portanto, estude, compreenda e faça bom uso.
“Para quem só conhece o martelo como ferramenta, parafuso é prego”. Não sei a origem desta frase, mas ela é sensacional.