Iterações com Yield e IEnumerable

Olá mancebos.

Hoje falarei sobre a instrução return yield e a interface IEnumerable<T> em C#, e como ambos, se usados juntos, podem melhorar a performance de iterações em listas, além de deixar o código mais limpo e bem estruturado.

Primeiramente, o que exatamente é o yield?
Bom, com certeza seu nome não é muito intuitivo. Mas, basicamente, ele é usado em junção com o return de um método (yield return) e ele mantêm o estado do método. Ou seja, todas as variáveis estarão com os mesmos valores, os objetos estarão com as mesmas referências de quando foi chamado anteriormente. Mas isso apenas em nível de iteração (será explicado mais a frente).

Parece útil? Sim. Pode-se utilizar isso em qualquer método? Não.

É aí que entra o IEnumerable. Para utilizar o yield em um método, é necessário que o mesmo tenha o retorno de IEnumerable<T>. Por quê? IEnumerable é a interface base que oferece suporte a iterações básicas, e quando declaramos o retorno do métodos com yield, estamos dizendo ao C# que nosso método será iterável.

Vejamos um exemplo de um métodos utilizando yieldIEnumerable:

public IEnumerable<int> NumerosNaturais()
{
    var numero = 0;

    while(true)
    {
        yield return numero++;
    }
}

Neste exemplo, estão presentes os elementos a quais comentei anteriormente, o tipo de retorno do método com IEnumerable<int> e a palavra-chave yield junto com return. Mas por quewhile(true)? Bem, como disse anteriormente, a utilização do IEnumerable torna o método iterável, o que significa que ele deve se comportar desse maneira. Vejamos como utilizar esse método:

foreach(var numero in NumerosNaturais())
{
    if (numero == 10) 
        break;

    Console.WriteLine("Número " + numero);
}

//Retorno: "Número 0", "Número 1", ..., "Número 9"

Simples, não? É este caso a que me referi antes. O yield mantêm o estado do método apenas por iteração. Enquanto a execução estiver no foreach, a variável numero do método NumerosNaturais vai ser continuamente incrementada, isso até a iteração parar, neste caso, até o número 9. Isso acontece porque a cada execução do foreach, a execução irá continuar do último yield return encontrado.

Essa é a vantagem do yield IEnumerable. Eu não tenho, em nenhum lugar, um registro dos números naturais, não criei nem inicializei nenhuma lista contendo-os. É possível carregar e utilizar apenas a quantidade necessária de registros.

Mas o quão prático é um if dentro do loop, apenas para delimitar a quantidade de registros? Muito pouco, com certeza. Neste caso, podemos pedir ajuda aos métodos LINQ, já que no final de contas, o nosso método retorna um IEnumerable:

foreach(var numero in NumerosNaturais().Take(10))
{
    Console.WriteLine("Número " + numero);
}

//Retorno: "Número 0", "Número 1", ..., "Número 9"

Dessa forma, temos um código que executará da mesma maneira do anterior, mas bem mais elegante, e com total suporte do LINQ. Poderíamos também, por exemplo, usar os 5 primeiros números múltiplos de 10:

foreach(var numero in NumerosNaturais().Select(n => n % 10 == 0).Take(5))
{
    Console.WriteLine("Número " + numero);
}

//Retorno: "Número 0", "Número 10", ..., "Número 40"
Anúncios

Tags:, , ,

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: