Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Escolha um iterador quando quiser retornar uma sequência cujos elementos chamadores podem consumir um de cada vez, sem primeiro compilar o resultado completo em uma coleção. Essa abordagem atende a valores gerados, filtros com fluxo de controle personalizado e sequências que os chamadores podem parar de ler antecipadamente. Em comparação com uma coleção concluída, um iterador muda quando o trabalho acontece, não apenas como você a escreve.
Dica
Este artigo ensina iteradores síncronos para desenvolvedores que conhecem métodos, loops e coleções. Para obter sintaxe completa yield e restrições, consulte a referência deyield instrução.
Um método iterador produz uma sequência de valores um de cada vez. Este artigo se concentra nos métodos de iterador que retornam IEnumerable<T>, cujos valores os chamadores geralmente consomem com uma foreach instrução.
Produzir elementos com yield return
Use yield return para fornecer o próximo elemento na sequência. O iterador a seguir seleciona leituras de temperatura aceitáveis de um sensor. Nesse cenário, -1 marca o fim dos dados do sensor.
int[] readings = [21, 27, 24, -1, 19];
IEnumerable<int> acceptedReadings =
SelectTemperatures(readings, maximum: 25);
Console.WriteLine("Sequence created.");
foreach (int temperature in acceptedReadings)
{
Console.WriteLine($"Accepted: {temperature}°C");
}
static IEnumerable<int> SelectTemperatures(
IEnumerable<int> readings,
int maximum)
{
foreach (int reading in readings)
{
Console.WriteLine($"Checking {reading}°C");
if (reading == -1)
{
yield break;
}
if (reading <= maximum)
{
yield return reading;
}
}
}
SelectTemperatures retorna IEnumerable<int>, que representa uma sequência de int valores. Cada yield return reading um fornece um valor para o foreach loop. Depois que o chamador manipula esse valor, o iterador continua com a próxima entrada.
Use o formulário genérico IEnumerable<T> para o código C# mais moderno. O argumento de tipo, como int, informa aos chamadores qual tipo de elemento a sequência contém.
Encerrar a sequência com yield break
Use yield break para encerrar um iterador antes que o controle atinja o final do método. No exemplo, o valor -1 sentinela significa que não há mais leituras disponíveis:
if (reading == -1)
{
yield break;
}
O iterador também termina naturalmente quando a execução atinge o final de seu corpo. Use yield break quando uma condição deve parar a produção de elementos imediatamente.
Consumir um iterador com foreach
Um iterador expõe a mesma IEnumerable<T> forma que muitas coleções .NET. Os chamadores podem usar foreach sem saber como a sequência produz seus elementos:
foreach (int temperature in SelectTemperatures(readings, 25))
{
Console.WriteLine($"Accepted: {temperature}°C");
}
O chamador solicita cada elemento conforme o loop avança. O iterador mantém sua posição entre solicitações e continua após o anterior yield return.
Entender a produção de elementos adiados
Chamar um método iterador não executa seu corpo imediatamente. O método começa a produzir elementos quando o chamador inicia a enumeração. Esse comportamento é chamado de execução adiada.
O exemplo é impresso Sequence created. antes de qualquer Checking ... mensagem. O iterador começa a verificar as leituras somente quando o foreach loop solicita seu primeiro elemento.
A execução adiada tem efeitos práticos:
- O chamador pode começar a processar antes que o iterador produza todos os elementos.
- O iterador pode parar mais cedo com
yield break. - Um chamador que nunca enumera a sequência não executa o corpo do iterador.
- Cada nova enumeração executa o iterador novamente.
Deixe a execução adiada clara na finalidade e na documentação do método. Os leitores não podem inferir o tempo de IEnumerable<T> execução sozinhos porque iteradores e coleções podem expor essa interface. Mantenha a produção de elementos livre de efeitos colaterais não relacionados porque os chamadores podem enumerar a sequência mais tarde ou mais de uma vez. As mensagens de diagnóstico do exemplo ilustram esse tempo.
Escolher um iterador ou uma coleção
Retorne um iterador quando os valores chegam naturalmente um de cada vez ou quando o chamador não precisa do resultado completo imediatamente. Retornar uma coleção concluída quando os chamadores precisarem de um instantâneo estável, acesso indexado ou enumeração repetida sem recalcular os elementos.
Ambas as abordagens podem retornar os mesmos elementos. O iterador deixa a produção do elemento sob o controle do chamador; um método que cria uma coleção conclui esse trabalho antes de retornar.
Use um loop comum quando quiser executar uma ação para cada item sem retornar uma sequência. Para um filtro ou transformação padrão, prefira uma operação LINQ, como Where ou Select; escreva um iterador quando a lógica de produção de elementos personalizada estiver mais clara como uma série de instruções.
Os métodos de iterador compõem com LINQ porque ambos usam IEnumerable<T>. Por exemplo, um chamador pode adicionar outro filtro:
var comfortableReadings = SelectTemperatures(readings, 25)
.Where(static temperature => temperature >= 18);
A operação iterador e LINQ permanecem adiadas comfortableReadingsaté que o código enumere.
Para sequências assíncronas, consulte Gerar e consumir fluxos assíncronos. Para padrões de enumeração personalizados e todas as yield restrições, use a referência de idioma.