Usando a declaração ‘yield’

O que é?

De modo simplificado, yield executa uma iteração personalizada retornando cada elemento, um de cada vez, sem a necessidade de criar coleções temporárias

Yield pode ser usado como uma maneira alternativa de criar tipos que funcionam com o loop foreach por meio de iteradores. Um iterador é um membro que especifica como os itens internos de um array ou lista devem ser retornados quando processados pelo foreach.

Segundo o site da Microsoft “Você usa uma instrução ‘yield return‘ para retornar cada elemento individualmente. A sequência retornada de um método usando iterador pode ser consumida em uma instrução foreach ou uma consulta LINQ.”

Como utilizar (Retirado da documentação)

A declaração de um iterador deve atender aos seguintes requisitos:
– O tipo de retorno deve ser IEnumerable, IEnumerable, IEnumerator ou IEnumerator.
– A declaração não pode ter os parâmetros in, ref nem out.

O tipo yield de um iterador que retorna IEnumerable ou IEnumerator é object. Se o iterador retornar IEnumerable ou IEnumerator, uma conversão implícita deverá existir do tipo da expressão na instrução ‘yield return‘ para o parâmetro de tipo genérico.

Você não pode incluir uma instrução yield return ou yield break em:
– Expressões lambda e métodos anônimos.
– Métodos que contêm blocos inseguros. Para obter mais informações, consulte unsafe no site da Microsoft.

Explicação do exemplo

No código exemplo é demonstrado o funcionamento do ‘yield return‘ em um foreach loop.

A ordem de execução do código segue a seguinte estrutura.
1 – Um objeto do tipo Product é criado
2 – Ao ser chamado no foreach, por ter a interface de IEnumerable ele ja chamao GetEnumerator()
3 – O loop retorna um objeto tipo Product
4 – No loop inicial ele ja atribui, e escreve na tela, informações sobre o Product
5 – O código volta para o loop interno do Product, escreve na tela a saída.

Os passos 3 a 5 são repetidos até o término do loop executado no GetEnumerator()

Exemplo:

using System;
using System.Collections;
using System.Collections.Generic;

namespace UsingYieldKeyword
{
    class Program
    {
        static void Main(string[] args)
        {
            var productList = new Product();
            foreach (Product prod in productList)
            {
                Console.WriteLine("Foreach Main Method - Product " + prod.Id);
            }
        }
    }

    public class Product : IEnumerable
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public double Price { get; set; }
        public string Type { get; set; }

        public static List<Product> GetProductsList()
        {
            Random rnd = new Random();
            var productList = new List<Product>();
            productList.Add(new Product() { Id = rnd.Next(10,99), Description = "Mouse", Price = 10.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = rnd.Next(10,99), Description = "Coffee", Price = 5.2, Type = "FOOD" });
            productList.Add(new Product() { Id = rnd.Next(10,99), Description = "Keyboard", Price = 15.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = rnd.Next(10,99), Description = "Fifa", Price = 7.3, Type = "GAME" });
            productList.Add(new Product() { Id = rnd.Next(10,99), Description = "Dota", Price = 10.3, Type = "GAME" });
            productList.Add(new Product() { Id = rnd.Next(10,99), Description = "Headphone", Price = 20.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = rnd.Next(10,99), Description = "Mouse pad", Price = 2.1, Type = "ELECTRONIC" });
            return productList;
        }
        public IEnumerator GetEnumerator()
        {
            int count = 0;
            foreach (var prod in GetProductsList())
            {
                yield return prod;
                count++;
                Console.WriteLine("Listed Product id: " + prod.Id + " With count: " + count);
            }
        }
    }
}
/* This will print
Foreach Main Method - Product 26
Listed Product id: 26 With count: 1
Foreach Main Method - Product 13
Listed Product id: 13 With count: 2
Foreach Main Method - Product 23
Listed Product id: 23 With count: 3
Foreach Main Method - Product 57
Listed Product id: 57 With count: 4
Foreach Main Method - Product 19
Listed Product id: 19 With count: 5
Foreach Main Method - Product 61
Listed Product id: 61 With count: 6
Foreach Main Method - Product 68
Listed Product id: 68 With count: 7
 */

Alguns detalhes importantes

Observe que esta implementação de GetEnumerator() itera sobre os subitens usando a lógica interna do foreach e retorna cada Product usando a sintaxe de ‘yeld return‘.
A palavra-chave yield é usada para especificar o valor (ou valores) a ser retornado à construção foreach.
No momento que o código atinge o yeld return, o local atual no contêiner é armazenado e a execução é reiniciada a partir desse ponto na próxima vez que o iterador é chamado.

Qualquer dúvida ou dicas, entre em contato: leandrolt@gmail.com

Principais referências

– https://docs.microsoft.com/pt-br/dotnet/csharp/language-reference/keywords/yield
– http://www.macoratti.net/17/02/cshp_yield1.htm
– https://www.infoworld.com/article/3122592/my-two-cents-on-the-yield-keyword-in-c.html
– https://stackoverflow.com/questions/39476/what-is-the-yield-keyword-used-for-in-c
– https://docs.microsoft.com/pt-br/dotnet/api/system.collections.ienumerable?view=netcore-3.1
– https://gabrielschade.github.io/2019/01/15/usando-ienumerable.html

Leave a Reply

Your email address will not be published. Required fields are marked *