Enumeradores (Enumerators) no Delphi

Geralmente o pessoal de Delphi conhece apenas o loop “for básico“, aquele “old school” :

 

outros até conhecem o loop “for-in“, que é utilizado para iterar elementos de um conjunto:

Com strings:

 

Com arrays:

 

Ele funciona também com outros tipos  (sets, por exemplo). Mas o que nem todo mundo sabe, é que é possível criar seus próprios enumeradores.

 

Enumeradores (Enumerator)

Você pode criar seu próprio enumerador para realizar iterações utilizando o loop “for-in”. Vamos imaginar uma classe de pedidos que armazene informações de seus itens. Assim, gostaríamos de fazer uma iteração entre os itens do pedido, utilizando o loop “for-in”. A primeira coisa a ser feita é criar:

Basicamente, criamos uma classe para simbolizar os itens do pedido. Ela possui apenas três informações:

  • CodProduto – O código do produto.
  • DescProduto – A descrição do produto.
  • Valor – Valor do produto.

Agora precisamos da classe do pedido:

Ela está bem simples, mas faremos algumas alterações daqui a pouco.

Precisamos criar uma classe enumeradora. Ela será responsável por armazenar toda a lógica de iteração do itens do pedido, tirando essa responsabilidade da classe de pedidos.

Uma coisa a saber sobre as classes enumeradoras, é que elas precisam obrigatoriamente possuir 2 métodos:

  • Uma função pública chamada MoveNext.
  • Uma propriedade read-only chamada Current.

A função MoveNext será chamada no loop para que o próximo elemento seja apresentado.

A propriedade será chamada para retornar o elemento atual da iteração.

Uma coisa a se observar aqui é que MoveNext sempre será chamado antes de Current, por isso, tome cuidado para que seu código trate esse comportamento.

Abaixo encontra-se a definição da classe enumeradora.

Agora que já temos nosso enumerador, vamos voltar à classe de pedidos e adicionar o último método para que tudo isso funcione.

  • Uma função pública chamada GetEnumerator.

GetEnumerator será o responsável por dizer ao compilador qual a classe responsavel pela iteração dos itens do pedido.

 

Colocando tudo para funcionar

Estabelecido as declarações, vamos para a implementação, começando com a classe enumeradora.

A classe enumeradora possui um contador interno chamdo FIndex, que zeramos para começarmos a iteração, no momento da criação.

FLista é a lista de pedidos que serão iterados.

GetCurrent será a função utilizada para o retorno do item do pedido atual da iteração.

MoveNext é a função responsável pela iteração dos itens do pedido, ou seja, aquela que movimenta o indice para “getCurrent” possa retornar novos itens do pedido.

Nada mais a se fazer com a classe enumeradora. Sua responsabilidade já foi satisfeita, ou seja, a iteração dos itens dentro da lista.

Voltando à classe de pedidos, devemos implementar a função GetEnumerator, para que o compilador saiba qual será nossa classe enumeradora:

Veja que precisei criar os itens manualmente aqui, como forma elucidativa, mas provavelmente você teria uma outra classe para o retorno dos itens ou mesmo uma busca desses itens no banco de dados. O mais importante aqui é a instrução:

Result := TMeuEnumerador.Create(Lista);

Ela retorna a criação da nossa classe enumeradora.

Todo o mecanismo está criado. Podemos agora simplesmente fazer uso de nossa nova estrutura:

Veja como o loop ficou muito mais simples, mais “clean”. Essa é a vantagem desse tipo de estrutura, seu charme.

Pronto! Simples, eficiente e elegante. Execute e veja os resultados. Abaixo encontra-se o fonte completo do exemplo:

Pronto para utilizar enumeradores em seus projeto?