Como os enumeradores e enumeráveis funcionam em C #?
As interfaces IEnumerable e IEnumerator do C # &’ s são usadas por coleções como Arrays e Lists para padronizar métodos de loop sobre elas e executar ações, como filtrar e selecionar com instruções LINQ. Discutiremos como eles funcionam e como usá-los.
O que é um enumerável?
O termo “ Enumerável ” define um objeto que deve ser iterado, passando por cima de cada elemento uma vez na ordem. Em C #, um Enumerable é um objeto como uma matriz, lista ou qualquer outro tipo de coleção que implemente a interface IEnumerable. Permite padronizar looping sobre coleções e permite o uso da sintaxe de consulta LINQ, bem como outros métodos de extensão úteis, como List. Where () ou List. Select ().
Tudo o que a interface IEnumerable requer é um método, GetEnumerator (), que retorna um IEnumerator. Então, o que os Enumeradores fazem?
Bem, IEnumerator requer dois métodos, MoveNext () e Current (). MoveNext é o método usado para passar por cima de cada item, aplicando qualquer tipo de lógica iteradora personalizada no processo, e Current é um método usado para obter o item atual após a conclusão de MoveNext. Você acaba com uma interface que define objetos que podem ser enumerados e como lidar com essa enumeração.
Por exemplo, toda vez que você escreve um loop foreach, está usando enumeradores. Na verdade, você não pode usar foreach em uma coleção que não implementa IEnumerable. Quando ele é compilado, um loop foreach como este:
foreach (elemento interno na lista) {// seu código}
Torna-se um loop while, que processa até que Enumerable esteja sem itens, chamando MoveNext a cada vez e definindo a variável do iterador como . Current.
Enumerador IEnumerator = list. GetEnumerator (); while (list. MoveNext ()) {element = (Int) enumerator. Current // your code}
Na maioria das vezes, você deseja implementar manualmente qualquer uma dessas coisas, já que Enumerables como Lists são projetados para serem usados em loops e com métodos LINQ. Mas, se você quiser criar sua própria classe de coleção, poderá fazê-lo implementando IEnumerable e retornando o enumerador da Lista em que você armazena os dados.
Para classes que possuem campos sobre os quais você gostaria de iterar, essa pode ser uma maneira fácil de limpar o código. Em vez de ter a matriz de dados pública e iterar no CustomCollection. dataArray, você pode apenas iterar no próprio CustomCollection. Obviamente, se você quiser que ele se comporte mais como uma lista adequada, você &’ precisará implementar outras interfaces como ICollection também.
Consultas LINQ usam execução adiada
O mais importante a observar sobre o LINQ é que as consultas nem sempre são executadas imediatamente. Muitos métodos retornam Enumerables e usam execução adiada. Em vez de fazer um loop bem quando a consulta é feita, ele realmente espera até que Enumerable seja usado no loop e, em seguida, faz a consulta durante MoveNext.
Vejamos um exemplo. Esta função pega uma lista de strings e imprime cada item que é maior que um determinado comprimento. Ele usa Where () para filtrar a lista e, em seguida, foreach para imprimir cada elemento.
Esta sintaxe é um pouco confusa, especialmente se você tem o hábito de usar var (o que definitivamente não deve ser feito aqui), pois pode parecer que você está gerando uma nova lista com Where () e, em seguida, iterando sobre essa lista. No caso de um loop foreach, um IEnumerable pode tomar o lugar de uma Lista, mas não é uma Lista — você não pode anexar ou remover itens.
C # é inteligente, porém, e em vez de iterar na lista duas vezes (o que dobraria o tempo de execução sem motivo e alocaria memória inútil), ele apenas joga a lógica de filtragem no loop foreach. Isso aqui não é exatamente para o qual seu código é traduzido, mas é uma boa ideia conceituá-lo assim, com a condição e a filtragem sendo destruídas dentro do foreach.
Nos bastidores, ele faz isso adicionando a consulta ao Enumerator e retornando um Enumerable que usará a lógica de Where () ao chamar Enumerable. MoveNext (). Se estiver interessado, você pode dar uma olhada em como System. Linq. Enumerable lida com isso em System. Core.
Na verdade, isso pode ter alguns efeitos negativos se você não tomar cuidado. E se, entre Where () e a execução, a coleção fosse modificada? Isso pode fazer com que as consultas pareçam ser realizadas fora de ordem.
Por exemplo, vamos dar a esta mesma função alguma entrada, mas em vez de imprimir imediatamente, vamos acrescentar uma nova palavra à lista antes de foreach. À primeira vista, pode parecer que isso filtrará as letras simples e produzirá “ Hello World, ” mas na verdade produz “ Hello World Banana, ” porque a filtragem não é aplicada até que MoveNext seja chamado durante a iteração real do foreach.
Isso é particularmente sorrateiro, uma vez que não estamos nem tocando na variável toPrint que é passada para o loop foreach. No entanto, se, em vez disso, você anexar . ToList () ao final da função Where, isso forçará o C # a realizar uma iteração e retornar uma nova lista. A menos que seja especificamente o que você deseja, é quase sempre melhor economizar tempo de execução e alocações de heap usando foreach com um Enumerable.
O que são corrotinas?
Corrotinas são funções especiais que podem pausar a execução e retornar à thread principal. Eles são comumente usados para executar ações longas que podem levar algum tempo para terminar, sem fazer com que o aplicativo trave enquanto espera pela rotina. Por exemplo, em jogos em que a taxa de quadros do aplicativo é muito importante, grandes problemas, mesmo na ordem de alguns milissegundos, prejudicariam a experiência do usuário.
Corrotinas estão intimamente ligadas aos Enumeradores, uma vez que são, na verdade, apenas funções que retornam um enumerador. Isso define um método iterador e você pode usá-lo. Você não precisa fazer muito; apenas altere o tipo de retorno da função para IEnumerator e, em vez de retornar algo, você pode apenas produzir return, que o define automaticamente como um enumerador sem fazer isso explicitamente.
Então, para interromper a execução em quadros diferentes, você só precisa gerar um retorno nulo sempre que quiser pausar a execução e executar mais do thread principal. Então, para usar este Enumerador, você precisará chamar a função e atribuí-la a uma variável, que você pode chamar MoveNext () em intervalos regulares.
Se você estiver usando o Unity, eles têm um controlador de co-rotina que pode lidar com o processamento de co-rotinas para você, apenas iniciando e interrompendo-as com seus métodos. No entanto, tudo o que ele realmente está fazendo é apenas chamar MoveNext () uma vez por quadro, verificando se ele pode processar mais e manipulando o valor de retorno se ele não for nulo. Você pode lidar com isso facilmente:
Claro, você pode querer funcionalidade extra, como produzir co-rotinas filhas que você &’ terá que adicionar a uma pilha de processamento e produzir expressões como WaitForSeconds ou esperar que funções assíncronas terminem, o que você &’ só precisa verificar uma vez por quadro (antes de chamar MoveNext) se a expressão retorna true, e então continuar o processamento. Dessa forma, a co-rotina irá parar completamente até que possa começar a funcionar novamente.
Via: How to Geek
Nenhum comentário