Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Choisissez un itérateur lorsque vous souhaitez retourner une séquence dont les appelants d’éléments peuvent en consommer une à la fois, sans générer d’abord le résultat complet d’une collection. Cette approche correspond aux valeurs générées, aux filtres avec un flux de contrôle personnalisé et aux séquences que les appelants peuvent cesser de lire tôt. Par rapport à une collection terminée, un itérateur change lorsque le travail se produit, pas seulement la façon dont vous l’écrivez.
Tip
Cet article explique les itérateurs synchrones pour les développeurs qui connaissent des méthodes, des boucles et des collections. Pour obtenir une syntaxe complète yield et des restrictions, consultez la référence de l’instructionyield.
Une méthode d’itérateur produit une séquence de valeurs une à la fois. Cet article se concentre sur les méthodes d’itérateur qui retournent IEnumerable<T>, dont les appelants de valeurs consomment généralement avec une foreach instruction.
Produire des éléments avec yield return
Permet yield return de fournir l’élément suivant dans la séquence. L’itérateur suivant sélectionne les lectures de température acceptables à partir d’un capteur. Dans ce scénario, -1 marque la fin des données du capteur.
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 retourne IEnumerable<int>, qui représente une séquence de int valeurs. Chacun yield return reading fournit une valeur à la foreach boucle. Une fois que l’appelant gère cette valeur, l’itérateur continue avec l’entrée suivante.
Utilisez le formulaire générique IEnumerable<T> pour le code C# le plus moderne. L’argument de type, tel que int, indique aux appelants quel type d’élément la séquence contient.
Mettre fin à la séquence avec yield break
Utilisez yield break pour mettre fin à un itérateur avant que le contrôle atteigne la fin de la méthode. Dans l’exemple, la valeur sentinelle signifie qu’aucune autre lecture -1 n’est disponible :
if (reading == -1)
{
yield break;
}
L’itérateur se termine également naturellement lorsque l’exécution atteint la fin de son corps. Utilisez yield break quand une condition doit arrêter immédiatement la production d’élément.
Consommer un itérateur avec foreach
Un itérateur expose la même IEnumerable<T> forme que de nombreuses collections .NET. Les appelants peuvent utiliser foreach sans savoir comment la séquence produit ses éléments :
foreach (int temperature in SelectTemperatures(readings, 25))
{
Console.WriteLine($"Accepted: {temperature}°C");
}
L’appelant demande chaque élément à mesure que la boucle avance. L’itérateur conserve sa position entre les requêtes et se poursuit après la précédente yield return.
Comprendre la production d’éléments différés
L’appel d’une méthode d’itérateur n’exécute pas immédiatement son corps. La méthode commence à produire des éléments lorsque l’appelant commence l’énumération. Ce comportement est appelé exécution différée.
L’exemple imprime Sequence created. avant tous les Checking ... messages. L’itérateur commence à vérifier les lectures uniquement lorsque la foreach boucle demande son premier élément.
L’exécution différée a des effets pratiques :
- L’appelant peut commencer à traiter avant que l’itérateur produise chaque élément.
- L’itérateur peut s’arrêter tôt avec
yield break. - Un appelant qui n’énumère jamais la séquence n’exécute pas le corps de l’itérateur.
- Chaque nouvelle énumération exécute à nouveau l’itérateur.
Effacez l’exécution différée dans l’objectif et la documentation de la méthode. Les lecteurs ne peuvent pas déduire le minutage de l’exécution uniquement IEnumerable<T> , car les itérateurs et les collections peuvent exposer cette interface. Conservez la production des éléments sans effets secondaires liés, car les appelants peuvent énumérer la séquence ultérieure ou plusieurs fois. Les messages de diagnostic de l’exemple illustrent ce minutage.
Choisir un itérateur ou une collection
Retournez un itérateur lorsque les valeurs arrivent naturellement une à la fois ou lorsque l’appelant n’a pas besoin du résultat complet immédiatement. Retournez une collection terminée lorsque les appelants ont besoin d’un instantané stable, d’un accès indexé ou d’une énumération répétée sans recalculer les éléments.
Les deux approches peuvent retourner les mêmes éléments. L’itérateur laisse la production d’élément sous le contrôle de l’appelant ; une méthode qui génère une collection fonctionne avant de retourner.
Utilisez une boucle ordinaire lorsque vous souhaitez effectuer une action pour chaque élément sans retourner une séquence. Pour un filtre ou une transformation standard, préférez une opération LINQ telle que Where ou Select; écrivez un itérateur lorsque la logique de production d’élément personnalisée est plus claire en tant qu’une série d’instructions.
Les méthodes d’itérateur composent avec LINQ, car les deux utilisent IEnumerable<T>. Par exemple, un appelant peut ajouter un autre filtre :
var comfortableReadings = SelectTemperatures(readings, 25)
.Where(static temperature => temperature >= 18);
L’itérateur et l’opération LINQ restent différés comfortableReadingsjusqu’à ce que le code énumère .
Pour les séquences asynchrones, consultez Générer et consommer des flux asynchrones. Pour les modèles d’énumération personnalisés et toutes les yield restrictions, utilisez la référence de langage.