Tutoriel : Combiner des techniques C# pour générer des étiquettes de badge

Une rencontre a besoin d’étiquettes de badge dans l’ordre des noms. Chaque participant demande une ou plusieurs copies, et chaque étiquette inclut un message pour le rôle du participant. Dans ce tutoriel, vous combinez de petites techniques C# pour produire les étiquettes sans collection distincte de chaînes mises en forme.

Ce didacticiel est destiné aux développeurs qui connaissent les méthodes, boucles et collections C# de base. Vous choisissez l’emplacement où appartiennent les opérations courtes, rendez les dépendances d’assistance explicites et décidez quand le programme produit des résultats. Pour connaître le raisonnement derrière ces choix, consultez Création de logiciels.

Prerequisites

Commencer par une étiquette par participant

  1. Créez un dossier nommé BadgeLabels et un fichier nommé Program.cs à l’intérieur de celui-ci.

  2. Copiez le code source complet dans la section suivante dans Program.cs. Utilisez ce même fichier pour chaque étape et expérience :

    #define BADGE_SORT
    #define BADGE_COPIES
    #define BADGE_FORMAT
    #define BADGE_COUNT
    // #define BADGE_DIAGNOSTICS
    // #define BADGE_REPEAT
    // #define BADGE_SNAPSHOT
    
    Attendee[] attendees =
    [
        new("Ben", "Host", 1),
        new("Ada", "Guest", 2)
    ];
    
    #if BADGE_SORT
    #if BADGE_DIAGNOSTICS
    Console.WriteLine("Before query definition.");
    #endif
    var orderedAttendees = attendees.OrderBy(
    #if BADGE_DIAGNOSTICS
        attendee =>
        {
            Console.WriteLine($"Sort key: {attendee.Name}");
            return attendee.Name;
        }, StringComparer.Ordinal);
    #else
        attendee => attendee.Name, StringComparer.Ordinal);
    #endif
    #if BADGE_DIAGNOSTICS
    Console.WriteLine("After query definition.");
    #endif
    #else
    var orderedAttendees = attendees;
    #endif
    
    #if BADGE_SNAPSHOT
    var attendeesToPrint = orderedAttendees.ToList();
    #else
    var attendeesToPrint = orderedAttendees;
    #endif
    
    int passes = 1;
    #if BADGE_REPEAT
    passes = 2;
    #endif
    
    for (int pass = 0; pass < passes; pass++)
    {
    #if BADGE_COUNT
        int expected = attendees.Sum(attendee => attendee.Copies);
        int printed = 0;
    #endif
    
        foreach (Attendee attendee in attendeesToPrint)
        {
    #if BADGE_COPIES
            var labels = CreateLabels(attendee);
    #if BADGE_DIAGNOSTICS
            Console.WriteLine($"Sequence created: {attendee.Name}");
    #endif
            foreach (string label in labels)
            {
                Console.WriteLine(label);
    #if BADGE_COUNT
                printed++;
    #endif
            }
    #else
            Console.WriteLine($"{attendee.Name} | {attendee.Role}");
    #endif
        }
    
    #if BADGE_COUNT
        if (printed != expected)
        {
            throw new InvalidOperationException("Label count doesn't match the request.");
        }
    
        Console.WriteLine($"Printed {printed} of {expected} requested labels.");
    #endif
    }
    
    #if BADGE_COPIES
    static IEnumerable<string> CreateLabels(Attendee attendee)
    {
    #if BADGE_DIAGNOSTICS
        Console.WriteLine($"Iterator started: {attendee.Name}");
    #endif
        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(attendee.Copies);
    
    #if BADGE_FORMAT
        string message = attendee.Role switch
        {
            "Guest" => "Welcome!",
            "Host" => "Ask me for help",
            _ => throw new ArgumentException(
                $"Unsupported role: {attendee.Role}.", nameof(attendee))
        };
    #endif
    
        for (int copy = 1; copy <= attendee.Copies; copy++)
        {
    #if BADGE_FORMAT
            yield return FormatLabel(
                attendee.Name, attendee.Role, message, copy, attendee.Copies);
    #else
            yield return $"{attendee.Name} | {attendee.Role} [{copy}/{attendee.Copies}]";
    #endif
        }
    
    #if BADGE_FORMAT
        static string FormatLabel(
            string name, string role, string message, int copy, int total) =>
            $"{name} | {role} | {message} [{copy}/{total}]";
    #endif
    }
    #endif
    
    record Attendee(string Name, string Role, int Copies);
    
  3. En haut du fichier, mettez en commentaire les quatre lignes actives #define. Laissez également les trois lignes d’expérimentation commentées.

  4. Dans ce dossier, exécutez l’application basée sur un fichier :

    dotnet run --file Program.cs
    

Le programme écrit :

Ben | Host
Ada | Guest

Le fichier contient chaque étape. À partir de maintenant, modifiez uniquement les lignes #define situées en haut, pas les corps de méthode ni les déclarations. Une directive #if inclut du code uniquement lorsque son symbole est défini ; une branche #else fournit l’alternative. Consultez compilation conditionnelle.

Supprimez les marques de commentaire d’une ligne d’étape supplémentaire à chaque étape et conservez les lignes d’étape précédentes activées :

Stage Symboles de l’étape active
Une étiquette par participant None
Trier les participants BADGE_SORT
Créer des copies BADGE_SORT, BADGE_COPIES
Mettre en forme les messages BADGE_SORT, BADGE_COPIES, BADGE_FORMAT
Vérifiez le nombre BADGE_SORT, BADGE_COPIES, BADGE_FORMAT, BADGE_COUNT

La source téléchargée active les quatre symboles d’étape, de sorte qu’elle exécute le programme final par défaut. Les trois autres symboles contrôlent les expériences facultatives et restent désactivés pendant la progression normale. Ces symboles utilisent un BADGE_ préfixe pour éviter les symboles définis par le Kit de développement logiciel (SDK) tels que TRACE.

Les extraits suivants mettent en évidence le code déjà dans votre fichier. Ne les copiez pas dans l’ensemble du programme.

Attendee[] attendees =
[
    new("Ben", "Host", 1),
    new("Ada", "Guest", 2)
];

La Attendee déclaration définit un enregistrement, un type qui regroupe les données associées et fournit l’égalité basée sur la valeur. Chaque participant a un Name, un Role et un nombre demandé de Copies. Un enregistrement correspond à ce petit modèle de données, car le programme transmet les données des participants entre les opérations sans les modifier. Pour plus d’informations sur ce type, consultez Enregistrements.

L’entrée fixe utilise un tableau et une expression de collection. Dans chaque new(...) appel, C# déduit Attendee du type d’élément de tableau ; consultez Target-typed new. Les instructions de niveau supérieur vous permettent d’exécuter l’exemple sans écrire de méthode Main.

La foreach boucle lit chaque participant et une chaîne interpolée insère leurs valeurs dans la sortie. La boucle ignore actuellement Copies.

Conservez cette petite entrée de données au fur et à mesure que vous développez le programme : Ben demande une copie, et Ada demande deux. Seuls les rôles Guest et Host sont pris en charge, et les nombres de copies doivent être positifs.

Trier avec une expression lambda

Pour placer les participants dans l’ordre des noms, supprimez les marques de commentaire de #define BADGE_SORT. Laissez les autres symboles commentés. La branche de tri définit cette requête :

var orderedAttendees = attendees.OrderBy(
#if BADGE_DIAGNOSTICS
    attendee =>
    {
        Console.WriteLine($"Sort key: {attendee.Name}");
        return attendee.Name;
    }, StringComparer.Ordinal);
#else
    attendee => attendee.Name, StringComparer.Ordinal);
#endif

Avec les diagnostics désactivés, la branche #else renvoie le lambda court. La boucle imprime les participants triés :

    foreach (Attendee attendee in attendeesToPrint)
    {
#if BADGE_COPIES
        var labels = CreateLabels(attendee);
#if BADGE_DIAGNOSTICS
        Console.WriteLine($"Sequence created: {attendee.Name}");
#endif
        foreach (string label in labels)
        {
            Console.WriteLine(label);
#if BADGE_COUNT
            printed++;
#endif
        }
#else
        Console.WriteLine($"{attendee.Name} | {attendee.Role}");
#endif
    }

Exécutez la même commande. La sortie place désormais Ada en premier :

Ada | Guest
Ben | Host

attendee => attendee.Name est une expression lambda, une fonction sans nom fournie où le code a besoin d’un comportement. Ici, le lambda sélectionne le nom selon lequel effectuer le tri. Le lambda reste inline, directement dans l’appel OrderBy, car il est court et son objectif est clair à cet endroit. Vous pouvez extraire la sélection dans une méthode d’assistance nommée, mais un nom de méthode n’expliquerait pas mieux cette sélection d’une propriété unique. Consultez les expressions lambda.

OrderByfait partie de LINQ (Language Integrated Query), d’un ensemble de fonctionnalités C# et d’API .NET pour les requêtes sur les données. Consultez les requêtes LINQ.

Cet exemple utilise la syntaxe de méthode, dans laquelle les méthodes LINQ sont appelées directement. En revanche, la syntaxe de requête utilise des clauses C# telles que from, orderbyet select:

var orderedAttendees =
    from attendee in attendees
    orderby attendee.Name
    select attendee;

Le compilateur traduit la syntaxe de requête en appels de méthode. La syntaxe de requête peut faciliter la lecture d’une requête avec plusieurs clauses ; la syntaxe de méthode conserve ce tri unique court et vous permet de passer un comparateur à OrderBy. L’exemple de syntaxe de requête utilise le comparateur de chaînes par défaut. Il ne garantit donc pas le même ordre d’une culture à l’autre. Conservez la version avec la syntaxe de méthode pour ce programme. Consultez la méthode LINQ et la syntaxe de requête.

Pour conserver la sortie indépendante de la culture de l’ordinateur, l’exemple utilise Ordinal pour les comparaisons de noms. Pour les noms courts ici, cet ordre est alphabétique. Consultez Trier les données avec LINQ.

La var déclaration permet au compilateur de déduire le type de la variable de requête. La orderedAttendees variable décrit une requête, et non une collection triée terminée. Pour énumérer une séquence, vous devez lire ses éléments un par un. OrderBy lit et trie tous les participants lorsque foreach demande un élément pour la première fois.

Observez l’ordre d’exécution

L’exécution différée signifie que le travail démarre lorsque le code énumère une séquence plutôt que lorsque le code définit la requête. Consultez Exécuter une requête. Utilisez la sortie de diagnostic pour voir la différence :

  1. Ne laissez activés que les symboles d’étape BADGE_SORT.

  2. Supprimez les marques de commentaire de #define BADGE_DIAGNOSTICS en haut du même fichier. Les branches de diagnostic entourent la définition de requête avec des messages et utilisent une expression lambda qui imprime chaque clé de tri :

    #if BADGE_SORT
    #if BADGE_DIAGNOSTICS
    Console.WriteLine("Before query definition.");
    #endif
    var orderedAttendees = attendees.OrderBy(
    #if BADGE_DIAGNOSTICS
        attendee =>
        {
            Console.WriteLine($"Sort key: {attendee.Name}");
            return attendee.Name;
        }, StringComparer.Ordinal);
    #else
        attendee => attendee.Name, StringComparer.Ordinal);
    #endif
    #if BADGE_DIAGNOSTICS
    Console.WriteLine("After query definition.");
    #endif
    #else
    var orderedAttendees = attendees;
    #endif
    
  3. Réexécutez dotnet run --file Program.cs . Avant de lire la sortie, prédisez si Sort key: apparaît avant ou après After query definition..

La sortie est la suivante :

Before query definition.
After query definition.
Sort key: Ben
Sort key: Ada
Ada | Guest
Ben | Host

Aucune clé de tri n’apparaît entre les deux messages de définition de requête. L’expression lambda s’exécute uniquement lorsque foreach demande le premier résultat. Les deux messages clés apparaissent avant la première étiquette, car OrderBy a besoin de toutes les clés avant de pouvoir déterminer quel participant vient en premier. Les clés suivent l’ordre d’entrée, Ben puis Ada ; les résultats suivent l’ordre trié, Ada puis Ben.

Le lambda de diagnostic a besoin à la fois d’un message et d’une clé retournée. Il utilise donc un corps de bloc d’instructions avec accolades et return, au lieu du corps d’expression unique d’origine.

Avec les diagnostics activés, essayez les deux commutateurs d’expérience dans le même fichier. Aucune modification des boucles ou de la requête n’est nécessaire :

  1. Décommentez #define BADGE_REPEAT et réexécutez :

    Before query definition.
    After query definition.
    Sort key: Ben
    Sort key: Ada
    Ada | Guest
    Ben | Host
    Sort key: Ben
    Sort key: Ada
    Ada | Guest
    Ben | Host
    

    Le second passage répète le tri. La variable de requête ne met pas en cache les résultats.

  2. Laissez BADGE_REPEAT activé, décommentez #define BADGE_SNAPSHOT et réexécutez :

    Before query definition.
    After query definition.
    Sort key: Ben
    Sort key: Ada
    Ada | Guest
    Ben | Host
    Ada | Guest
    Ben | Host
    

    Les deux messages clés ne s’affichent qu’une seule fois, pendant ToList, avant que l’un ou l’autre passage n’imprime les étiquettes. Les deux passes lisent les participants stockés.

Ces commutateurs sélectionnent la séquence à énumérer et le nombre d’itérations :

#if BADGE_SNAPSHOT
var attendeesToPrint = orderedAttendees.ToList();
#else
var attendeesToPrint = orderedAttendees;
#endif

int passes = 1;
#if BADGE_REPEAT
passes = 2;
#endif

L’exécution immédiate signifie qu’une opération s’exécute immédiatement au lieu d’attendre une énumération ultérieure. ToList exécute immédiatement la requête et stocke ses résultats dans une liste. Les deux passes lisent maintenant les participants stockés sans réexécuter le tri. En revanche, la définition de la requête OrderBy reporte toujours le tri : elle lit et met en mémoire tampon toutes les entrées uniquement lorsque l’énumération commence. La mise en mémoire tampon ne signifie pas que la requête s’exécute lorsque vous la définissez. Utilisez un instantané lorsque vous devez réutiliser les résultats sans les recalculer ; conservez la requête différée lorsque vous souhaitez que chaque énumération lise l’entrée actuelle. Consultez Composez des requêtes avec des résultats mis en cache.

Avant de continuer, commentez BADGE_DIAGNOSTICS, BADGE_REPEAT et BADGE_SNAPSHOT encore. Laissez BADGE_SORT activé. Exécutez l’application pour confirmer que seules les deux étiquettes triées apparaissent.

Produire les copies demandées avec un itérateur

Pour dupliquer chaque participant en autant d’étiquettes que demandé, décommentez #define BADGE_COPIES avec BADGE_SORT. La boucle sélectionne maintenant la branche BADGE_COPIES affichée précédemment et appelle l’itérateur déjà dans le fichier :

#if BADGE_COPIES
static IEnumerable<string> CreateLabels(Attendee attendee)
{
#if BADGE_DIAGNOSTICS
    Console.WriteLine($"Iterator started: {attendee.Name}");
#endif
    ArgumentOutOfRangeException.ThrowIfNegativeOrZero(attendee.Copies);

#if BADGE_FORMAT
    string message = attendee.Role switch
    {
        "Guest" => "Welcome!",
        "Host" => "Ask me for help",
        _ => throw new ArgumentException(
            $"Unsupported role: {attendee.Role}.", nameof(attendee))
    };
#endif

    for (int copy = 1; copy <= attendee.Copies; copy++)
    {
#if BADGE_FORMAT
        yield return FormatLabel(
            attendee.Name, attendee.Role, message, copy, attendee.Copies);
#else
        yield return $"{attendee.Name} | {attendee.Role} [{copy}/{attendee.Copies}]";
#endif
    }

#if BADGE_FORMAT
    static string FormatLabel(
        string name, string role, string message, int copy, int total) =>
        $"{name} | {role} | {message} [{copy}/{total}]";
#endif
}
#endif

Réexécutez l’application :

Ada | Guest [1/2]
Ada | Guest [2/2]
Ben | Host [1/1]

CreateLabels est un itérateur, une fonction qui produit des éléments de séquence un par un. Son IEnumerable<T> type de retour, écrit en tant que IEnumerable<string>, représente une séquence de chaînes. Chaque yield return fournit une étiquette à la boucle interne foreach, qui l’imprime avant de demander l’étiquette suivante. Voir Itérateurs.

La for boucle compte les copies de 1 à attendee.Copies. Un participant produit autant de chaînes qu’il y a de requêtes Copies. Une collection fonctionne également, mais l’appelant n’a besoin de chaque étiquette qu’une seule fois. L’itérateur évite une collection d’étiquettes distincte et garde la boucle de numéro de copie regroupée. Les boucles externes et internes foreach séparent l’ordre de tri des participants de la production d’étiquettes ; l’appelant reste responsable de l’impression.

Appeler CreateLabels(attendee) n’exécute pas son corps. Comme la requête LINQ, l’itérateur utilise l’exécution différée. Le processus interne foreach démarre ce travail, y compris la vérification de copie conforme. Une nouvelle énumération parcourt à nouveau l’itérateur. Contrairement à OrderBy, qui lit et trie tous les participants avant son premier résultat, cet itérateur fournit une étiquette sans créer les étiquettes restantes.

Pour observer l’ordre d’exécution de l’itérateur, décommentez à nouveau #define BADGE_DIAGNOSTICS. Laissez BADGE_REPEAT et BADGE_SNAPSHOT désactivés. Les diagnostics affichent désormais à la fois le tri et l’itérateur :

Before query definition.
After query definition.
Sort key: Ben
Sort key: Ada
Sequence created: Ada
Iterator started: Ada
Ada | Guest [1/2]
Ada | Guest [2/2]
Sequence created: Ben
Iterator started: Ben
Ben | Host [1/1]

Pour chaque participant, le message créé par la séquence s’affiche avant le message de démarrage de l’itérateur et les étiquettes. La création de la séquence n’entre pas dans le corps de l’itérateur ; le fait de demander son premier élément, si. Mettez BADGE_DIAGNOSTICS en commentaire à nouveau avant de continuer.

Les mêmes contrôles d’expérience restent disponibles dans les phases ultérieures. BADGE_REPEAT énumère les participants deux fois et crée à nouveau la séquence d’étiquettes de chaque participant. BADGE_SNAPSHOT met uniquement en cache les participants triés, et non les chaînes d’étiquette, de sorte qu’il empêche un autre tri, mais n’empêche pas l’itérateur de s’exécuter à nouveau sur chaque passe.

La ThrowIfNegativeOrZero vérification signale une entrée non valide au lieu de produire silencieusement aucune étiquette. Une exception signale un échec qui interrompt l’exécution normale ; consultez Créer et lever des exceptions. Ici, un nombre de copies non valide arrête le programme au lieu d’ignorer silencieusement ce participant.

Calculer un message et nommer l’étape de mise en forme

Chaque rôle a besoin d’un message différent. Décommentez #define BADGE_FORMAT, et laissez BADGE_SORT et BADGE_COPIES activés. Le même itérateur inclut désormais le calcul du message :

#if BADGE_FORMAT
    string message = attendee.Role switch
    {
        "Guest" => "Welcome!",
        "Host" => "Ask me for help",
        _ => throw new ArgumentException(
            $"Unsupported role: {attendee.Role}.", nameof(attendee))
    };
#endif

Il sélectionne également la branche yield return FormatLabel(...) et inclut cette fonction auxiliaire locale :

#if BADGE_FORMAT
    static string FormatLabel(
        string name, string role, string message, int copy, int total) =>
        $"{name} | {role} | {message} [{copy}/{total}]";
#endif

Réexécutez l’application :

Ada | Guest | Welcome! [1/2]
Ada | Guest | Welcome! [2/2]
Ben | Host | Ask me for help [1/1]

L’expressionswitch calcule le message une fois par participant, avant la boucle de copie. Une expression convient parce que chaque rôle sélectionne une valeur à affecter à message. Une if/else chaîne ou une switch instruction conditionnelle fonctionnerait, mais répéterait l’affectation dans chaque branche.

Le filtrage par motif teste une expression par rapport à un motif spécifié. Voici, attendee.Role l’expression d’entrée, et les motifs constants"Guest" et "Host" testent sa valeur évaluée pour sélectionner le message correspondant. Le discard pattern _ correspond à tout autre rôle et lève une exception, de sorte que les rôles non pris en charge ne reçoivent pas de message par défaut trompeur. Voir filtrage par motif.

L’opérateur nameoffournit à l’exception le nom du paramètre attendee. Contrairement à une chaîne codée en dur, ce nom reste correct si vous renommez le paramètre avec un outil de refactorisation.

FormatLabel est une fonction locale, une fonction nommée déclarée à l’intérieur d’une autre fonction. Comme seule l’opération de mise en forme nécessite CreateLabels, son placement à l’intérieur de CreateLabels limite la fonction utilitaire à l’opération qui l’utilise. Une méthode membre privée sur une classe permettrait de rendre la fonction utilitaire disponible pour d’autres membres de cette classe. Choisissez cette portée plus large si plusieurs opérations nécessitent la même opération de mise en forme. Consultez les fonctions locales.

Le nom FormatLabel vous permet de suivre la boucle de copie sans lire les détails de mise en forme. Conserver directement la chaîne interpolée dans yield return fonctionnerait également, comme à l’étape précédente. Le nom devient plus utile maintenant qu’une étiquette inclut un message spécifique au rôle. Le corps d’expression de l’assistant => retourne l’unique chaîne mise en forme.

Toutes les entrées de mise en forme arrivent via des paramètres. Une fonction locale non statique peut capturer ou utiliser des variables à partir de sa portée environnante. Le static modificateur empêche cette capture, de sorte que ses dépendances restent explicites. Voir les paramètres et l’état capturé.

Étant donné que CreateLabels est toujours un itérateur, la vérification du rôle s’exécute uniquement au démarrage de l’énumération. Pour cette entrée contrôlée, ces vérifications relèvent de la production d’étiquettes. Le programme ne promet pas de valider tous les participants avant que des étiquettes ne soient imprimées.

Vérifier le total et exécuter le programme complet

Pour comparer la production réelle d’étiquettes avec le nombre demandé, supprimez les marques de commentaire de #define BADGE_COUNT. Les quatre symboles d’étape sont désormais activés. Laissez les trois symboles d’expérience commentés pour la sortie finale normale.

La configuration du comptage s’exécute avant la boucle sur les participants :

#if BADGE_COUNT
    int expected = attendees.Sum(attendee => attendee.Copies);
    int printed = 0;
#endif

Sum utilise l’exécution immédiate pour ajouter les nombres de copies à partir du tableau d’entrée. Contrairement à OrderBy, il retourne un nombre, et non une séquence à énumérer ultérieurement. Sa fonction lambda, attendee => attendee.Copies sélectionne le nombre de copies en ligne. Comme pour la sélection du nom, une méthode d’assistance distincte ne clarifierait pas cette courte expression. Une boucle avec un accumulateur fonctionne également ; Sum indique directement que vous voulez un total. Consultez les méthodes LINQ courantes.

printed++L’incrément dans la boucle label augmente le compteur uniquement lorsque la boucle reçoit un label. Après cette boucle, l’instructionif compare ce nombre au total demandé et lève une exception s’ils diffèrent :

#if BADGE_COUNT
    if (printed != expected)
    {
        throw new InvalidOperationException("Label count doesn't match the request.");
    }

    Console.WriteLine($"Printed {printed} of {expected} requested labels.");
#endif

Vous êtes arrivé à la configuration par défaut du programme complet que vous avez copié au début. Aucune méthode ou déclaration n’a besoin d’être modifiée :

#define BADGE_SORT
#define BADGE_COPIES
#define BADGE_FORMAT
#define BADGE_COUNT
// #define BADGE_DIAGNOSTICS
// #define BADGE_REPEAT
// #define BADGE_SNAPSHOT

Exécutez-le avec dotnet run --file Program.cs. La sortie est la suivante :

Ada | Guest | Welcome! [1/2]
Ada | Guest | Welcome! [2/2]
Ben | Host | Ask me for help [1/1]
Printed 3 of 3 requested labels.

Le tableau d’entrée est déjà en mémoire. Sum le lit immédiatement, OrderBy le trie lorsque la boucle du participant commence et CreateLabels produit des chaînes à mesure que la boucle interne avance. Le programme ne génère jamais une collection distincte d’étiquettes. Pour obtenir des conseils plus larges sur les requêtes, consultez LINQ et les collections.

Pour revoir les diagnostics avec le programme final, activez BADGE_DIAGNOSTICS à lui seul parmi les symboles d’expérience. La sortie est la suivante :

Before query definition.
After query definition.
Sort key: Ben
Sort key: Ada
Sequence created: Ada
Iterator started: Ada
Ada | Guest | Welcome! [1/2]
Ada | Guest | Welcome! [2/2]
Sequence created: Ben
Iterator started: Ben
Ben | Host | Ask me for help [1/1]
Printed 3 of 3 requested labels.

Si vous activez également BADGE_REPEAT, chaque exécution vérifie et signale son propre décompte. Avec BADGE_SNAPSHOT activé, les clés de tri n’apparaissent qu’une seule fois, mais les messages d’itérateur, les étiquettes et le rapport de comptage apparaissent toujours sur chaque passe. Mettez en commentaire les symboles d’expérience pour restaurer la sortie finale normale.

Summary

Chaque technique sert une partie différente de la même tâche :

  • Lambdas et LINQ sélectionnent des noms et les quantités copiées directement pour le tri et le total.
  • Un itérateur exprime une production un-à-plusieurs personnalisée et laisse la consommation d’étiquettes à l’appelant.
  • Une switch expression calcule une valeur spécifique au rôle et rend les rôles non pris en charge explicites.
  • Une fonction locale nomme l’étape de mise en forme, limite son étendue et indique ses entrées.

Choisissez ces formes lorsque leur étendue, leurs dépendances et leur ordre d’exécution correspondent à l’opération. Une boucle directe, une méthode partagée ou une collection complète peut mieux correspondre à d’autres appelants.