チュートリアル: C# の手法を組み合わせてバッジ ラベルを生成する

Meetup には、名前順にバッジ ラベルが必要です。 各出席者は 1 つ以上のコピーを要求し、各ラベルには出席者のロール用メッセージが含まれます。 このチュートリアルでは、小さな C# 手法を組み合わせて、書式設定された文字列の個別のコレクションなしでラベルを生成します。

このチュートリアルは、基本的な C# メソッド、ループ、コレクションを知っている開発者を対象としています。 短い操作が属する場所を選択し、ヘルパーの依存関係を明示的にし、プログラムが結果を生成するタイミングを決定します。 これらの選択の理由については、ソフトウェアの構築を参照してください。

前提条件

  • .NET 10 SDK。
  • テキスト エディターとターミナル。

出席者ごとに 1 つのラベルを用意する

  1. BadgeLabelsという名前のフォルダーと、その中にProgram.csという名前のファイルを作成します。

  2. 次のセクションの完全なソースをProgram.csにコピーしてください。 すべての手順と実験に同じファイルを使用してください。

    #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. ファイルの上部にある 4 つのアクティブな #define 行をコメントアウトしてください。 3つの実験行もコメントアウトしたままにしてください。

  4. そのフォルダーから、ファイルベースのアプリを実行してください:

    dotnet run --file Program.cs
    

プログラムは次のように出力します。

Ben | Host
Ada | Guest

ファイルにはすべての段階が含まれています。 今後は、メソッド本体や宣言ではなく、一番上の #define 行のみを変更してください。 #if ディレクティブには、そのシンボルが定義されている場合にのみコードが含まれます。#elseブランチは代替手段を提供します。 条件付きコンパイルを参照してください。

各ステップでステージ行をさらに1行ずつコメント解除し、前のステージ行を有効のままにします。

段階 アクティブステージシンボル
出席者ごとに 1 つのラベル None
出席者の並べ替え BADGE_SORT
コピーを作成 BADGE_SORT、BADGE_COPIES
メッセージを整形する BADGE_SORT、BADGE_COPIES、BADGE_FORMAT
カウントを確認する BADGE_SORT、BADGE_COPIES、BADGE_FORMAT、BADGE_COUNT

ダウンロードしたソースでは、4 つのステージ シンボルがすべて有効になるため、既定で最終版のプログラムが実行されます。 他の 3 つのアイコンは、オプションの実験を制御し、通常の進行中はオフの状態を維持します。 これらのシンボルは、BADGE_ などの SDK で定義されたシンボルを回避するために、TRACE プレフィックスを使用します。

次の抜粋では、ファイルに既に含まれているコードが強調表示されています。 プログラム全体にわたってコピーしないでください。

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

Attendee宣言では、レコード (関連するデータをグループ化し、値ベースの等価性を提供する型) を定義します。 各出席者には、 Name、 Role、および要求された数の Copiesがあります。 レコードはこの小さなデータ モデルに適合します。これは、プログラムが変更せずに操作間で出席者データを渡すからです。 このタイプの詳細については、レコードを参照してください。

固定入力では、 配列とコレクション式が使用されます。 各 new(...) 呼び出しでは、C# は配列要素型から Attendee を推論します。 ターゲット型の newを参照してください。 トップレベル ステートメント を使用すると、Main というメソッドを記述せずに例を実行できます。

foreach ループは各出席者を読み取り、補間された文字列によって値が出力に挿入されます。 現在、ループは Copiesを無視します。

プログラムを開発するときに、この小さな入力を保持します。Ben は 1 つのコピーを要求し、Ada は 2 つを要求します。 サポートされているロールは Guest と Host のみであり、コピー数は正である必要があります。

ラムダを使用した並べ替え

出席者を名前順に並べ替えるには、#define BADGE_SORTをコメント解除します。 他の記号はコメントアウトしたままにします。並べ替え分岐では、次のクエリが定義されます。

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

診断がオフの場合、 #else ブランチは短いラムダを提供します。 ループは、並べ替えられた出席者を出力します。

    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
    }

同じコマンドを実行します。 出力では、Ada が最初になります。

Ada | Guest
Ben | Host

attendee => attendee.Name は ラムダ式であり、コードで動作が必要な場合に指定される名前のない関数です。 ここで、ラムダは並べ替えの基準となる名前を選択します。 このラムダは、短く、その目的もその場では明確であるため、インラインのまま、OrderBy呼び出しで直接記述されています。 選択を名前付きヘルパー メソッドに抽出することもできますが、メソッド名では、この 1 つのプロパティの選択をうまく説明できません。 ラムダ式を参照してください。

OrderByは、データに対するクエリ用の C# 機能と.NET API のセットである言語統合クエリ (LINQ) の一部です。 LINQ クエリを参照してください。

この例では、LINQ メソッドを直接呼び出すメソッド構文を使用します。 これに対し、 クエリ構文 では、 from、 orderby、 selectなどの C# 句が使用されます。

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

コンパイラは、クエリ構文をメソッド呼び出しに変換します。 クエリ構文を使用すると、複数の句を含むクエリを読みやすくすることができます。メソッド構文は、この単一の並べ替えを短く保ち、比較子を OrderByに渡すことができます。 クエリ構文の例では、既定の文字列比較子が使用されるため、カルチャ間で同じ順序が保証されるわけではありません。 このプログラムではメソッド構文版を維持してください。 LINQ メソッドとクエリ構文を参照してください。

出力をコンピューターのカルチャに依存しない状態に保つために、サンプルでは名前の比較に Ordinal を使用します。 ここでの短い名前の場合、その順序はアルファベット順です。 LINQ を使用したデータの並べ替えを参照してください。

var宣言を使用すると、コンパイラはクエリ変数の型を推論できます。 orderedAttendees変数は、完了した並べ替えられたコレクションではなく、クエリを記述します。 シーケンスを 列挙 するとは、要素を 1 つずつ順に読み取ることです。 OrderBy は、最初にforeachが要素を要求したときに、すべての出席者を読み取って並べ替えます。

実行順序を観察する

遅延実行 とは、コードがクエリを定義するときではなく、コードがシーケンスを列挙したときに作業が開始されるということを意味します。 クエリを実行するを参照してください。 診断出力を使用して、違いを確認できます。

  1. ステージ シンボルの中で BADGE_SORT のみを有効のままにします。

  2. 同じファイルの先頭にある #define BADGE_DIAGNOSTICS のコメントを解除します。 診断ブランチは、クエリ定義をメッセージで囲み、各並べ替えキーを出力するラムダを使用します。

    #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. dotnet run --file Program.csをもう一度実行します。 出力を読み取る前に、Sort key: が After query definition. の前後どちらに表示されるかを予測します。

出力は次のとおりです。

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

2 つのクエリ定義メッセージの間に並べ替えキーは表示されません。 ラムダは、 foreach が最初の結果を要求した場合にのみ実行されます。 どちらのキー メッセージも最初のラベルの前に表示されます。OrderBy は、どの出席者が先に来るかを判断する前に、すべてのキーを必要とするためです。 キーは入力順序に従います。つまり、Ben、次にAdaです。結果は並べ替えられた順序に従います。つまり、Ada、次にBenです。

診断用ラムダ式にはメッセージと戻り値となるキーの両方が必要であるため、元の単一式の本体の代わりに、括弧とreturnを用いたブロックの本文が使用されています。

診断をオンにして、同じファイル内の 2 つの実験スイッチを試してください。 ループまたはクエリを変更する必要はありません。

  1. #define BADGE_REPEATコメントを解除し、もう一度実行してください。

    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
    

    2 番目のパスは並べ替えを繰り返します。 クエリ変数は結果をキャッシュしません。

  2. BADGE_REPEATを有効のままにし、#define BADGE_SNAPSHOTのコメントを解除して、もう一度実行します。

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

    2 つのキー メッセージは、どちらのパスでもラベルを印刷する前の ToList 中に 1 回だけ表示されるようになりました。 両方の処理は、保存されている出席者を読み取ります。

これらのスイッチは、列挙するシーケンスとパスの数を選択します。

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

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

即時実行とは、操作が後で列挙されるのを待たずに直ちに実行されることを意味します。 ToList はクエリを直ちに実行し、その結果をリストに格納します。 どちらのパスも、並べ替えを再実行せずに、保存されている出席者を読み取るようになりました。 これに対し、 OrderBy クエリを定義しても並べ替えが延期されます。列挙が開始されたときにのみ、すべての入力が読み取られ、バッファーされます。 バッファリングは、定義時にクエリが実行されることを意味するわけではありません。 再計算せずに結果を再利用する必要がある場合は、スナップショットを使用します。列挙のたびに現在の入力を読み取らせたい場合は、遅延クエリを保持します。 キャッシュされた結果を使用したクエリの作成を参照してください。

続行する前に、BADGE_DIAGNOSTICS、BADGE_REPEAT、BADGE_SNAPSHOT をもう一度コメントアウトしてください。 BADGE_SORT有効のままにします。 アプリを実行して、並べ替えられた 2 つのラベルのみが表示されることを確認します。

反復子を使用して要求されたコピーを生成する

各出席者を要求された数のラベルに展開するには、#define BADGE_COPIESとBADGE_SORTのコメントを解除します。 ループは、前に示した BADGE_COPIES ブランチを選択し、ファイル内に既にある反復子を呼び出します。

#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

アプリをもう一度実行してください:

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

CreateLabels は 反復子であり、シーケンス要素を 1 つずつ順に生成する関数です。 その IEnumerable<T> 戻り値の型は、IEnumerable<string> と記述され、文字列のシーケンスを表します。 各 yield return は、内部 foreach ループに 1 つのラベルを提供し、内部 foreach ループはそのラベルを出力してから次のラベルを要求します。 イテレーターを参照してください。

for ループは、1 からattendee.Copiesまでのコピーをカウントします。 1 人の出席者が、 Copies 要求と同数の文字列を生成します。 コレクションも機能しますが、呼び出し元は各ラベルを 1 回だけ必要とします。 反復子は別個のラベルコレクションを使わず、copy-numberループをまとめて扱います。 外側と内側の foreach ループは、出席者の順序とラベルの生成を分離します。呼び出し元は引き続き印刷を担当します。

CreateLabels(attendee)を呼び出しても本文は実行されません。 LINQ クエリと同様に、反復子は遅延実行を使用します。 内側のforeachは、正のコピー チェックを含め、その処理を開始します。 新しい列挙を行うと、イテレータが再度実行されます。 最初の結果の前にすべての出席者を読み取って並べ替える OrderByとは異なり、この反復子は残りのラベルを作成せずにラベルを提供します。

反復子の実行順序を確認するには、もう一度 #define BADGE_DIAGNOSTICS のコメントを解除します。 BADGE_REPEATとBADGE_SNAPSHOTをオフにしておいてください。 診断に並べ替えと反復子の両方が表示されるようになりました。

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]

出席者ごとに、反復子が開始されたメッセージとラベルの前に、シーケンスで作成されたメッセージが表示されます。 シーケンスを作成しても反復子本体に入ることはありません。最初の要素を要求すると入ります。 続行する前に、もう一度BADGE_DIAGNOSTICSをコメントアウトしてから続行してください。

同じ実験コントロールは、後の段階でも引き続き利用可能です。 BADGE_REPEAT は、出席者を 2 回列挙し、各出席者のラベル シーケンスを再度作成します。 BADGE_SNAPSHOT は、ラベル文字列ではなく並べ替えられた出席者のみをキャッシュするため、別の並べ替えを防ぎますが、各パスで反復子が再度実行されるのを防ぐことはありません。

ThrowIfNegativeOrZero チェックでは、黙ってラベルを何も出力しないのではなく、無効な入力が報告されます。 例外は、通常の実行を中断する失敗を報告します。例外の作成とスローを参照してください。 ここでは、無効なコピー数は、その出席者をサイレント スキップするのではなく、プログラムを停止します。

メッセージを作成し、書式設定手順に名前を付ける

各ロールには異なるメッセージが必要です。 #define BADGE_FORMATのコメントを解除し、BADGE_SORTとBADGE_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

また、 yield return FormatLabel(...) ブランチも選択され、次のローカル ヘルパーが含まれます。

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

アプリをもう一度実行してください:

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

switch式は、コピー ループの前に各出席者について1回、メッセージを計算します。 各ロールが messageに割り当てる 1 つの値を選択するため、式は成り立ちます。 if / else チェーンまたは switch ステートメントは機能しますが、各分岐で割り当てを繰り返します。

パターン マッチングは 、指定されたパターンに対して式をテストします。 ここで、attendee.Roleは入力式であり、定数パターン"Guest"と"Host"は、その評価結果に基づいて一致するメッセージを選択します。 破棄パターン_は他のロールと一致し、例外をスローするため、サポートされていないロールは誤解を招く既定のメッセージを受け取りません。 パターン マッチングを参照してください。

nameof演算子は、例外にパラメータ名attendeeを指定します。 ハードコーディングされた文字列とは異なり、リファクタリング ツールを使用してパラメーターの名前を変更しても、その名前は正しいままです。

FormatLabel は ローカル関数であり、別の関数内で宣言された名前付き関数です。 書式設定操作が必要なのは CreateLabels だけなので、CreateLabels 内での配置により、ヘルパーはそれを使用する操作に限定されます。 クラスのプライベート メンバー メソッドであれば、そのヘルパーをそのクラスの他のメンバーから利用できるようになります。 複数の操作で同じ書式設定操作が必要な場合は、より広範なスコープを選択します。 「ローカル関数」を参照してください。

名前FormatLabelを使用すると、書式設定の詳細を読まなくてもコピー ループを追うことができます。 補間された文字列を直接 yield return 内に記述しても、前の手順と同様に機能します。 ラベルにロール固有のメッセージが含まれるようになったため、名前がより有用になります。 ヘルパーの => 式本体 は、その書式設定済み文字列を返します。

すべての書式設定入力は、パラメーターを介して渡されます。 非静的ローカル関数は、周囲のスコープから変数を キャプチャまたは使用できます。 static修飾子は、そのキャプチャを防ぐため、その依存関係は明示的なままとなります。 パラメーターとキャプチャされた状態を参照してください。

CreateLabelsはまだ反復子であるため、ロール チェックは列挙が開始されるときにのみ実行されます。 この制御された入力の場合、これらのチェックはラベル作成で扱います。 プログラムは、ラベルを印刷する前にすべての出席者を検証するとは限りません。

合計を確認し、プログラム全体を実行する

実際のラベルの生産と要求された数を比較するには、 #define BADGE_COUNTコメントを解除します。 4 つのステージ シンボルがすべて有効になりました。 通常の最終出力では、3 つの実験シンボルをコメントアウトしたままにします。

カウント設定は、出席者ループの前に実行されます。

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

Sum では、即時実行を使用して、入力配列からコピー数を追加します。 OrderByとは異なり、後で列挙するシーケンスではなく、1 つの数値を返します。 そのラムダ attendee => attendee.Copies、コピー数をインラインで選択します。 名前の選択と同様に、別のヘルパー メソッドでは、この短い式は明確になりません。 アキュムレータを含むループも機能します。Sum を使えば、合計したいことを直接示せます。 一般的な LINQ メソッドを参照してください。

ラベル ループ内の printed++ increment は、ループがラベルを受け取った場合にのみカウンターを増加させます。 そのループの後、if ステートメント はそのカウントを要求された合計と比較し、異なる場合は例外をスローします。

#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

開始時にコピーした完全なプログラムの既定の構成が表示されています。 変更が必要なメソッドまたは宣言はありません。

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

dotnet run --file Program.csで実行してください。 出力は次のとおりです。

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

入力配列は既にメモリ内にあります。 Sum は、それをすぐに読み取り、OrderBy は、出席者ループが始まるとそれを並べ替え、CreateLabels は内部ループが進むにつれて文字列を生成します。 プログラムは、ラベルの別のコレクションを作成することはありません。 より広範なクエリ ガイダンスについては、LINQ とコレクションを参照してください。

最終的なプログラムで診断を見直すには、実験シンボルの中では BADGE_DIAGNOSTICS だけを有効にします。 出力は次のとおりです。

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.

BADGE_REPEATも有効にした場合、各パスは独自のカウントをチェックして報告します。 BADGE_SNAPSHOTを有効にすると、並べ替えキーは 1 回だけ表示されますが、反復子メッセージ、ラベル、カウント レポートは引き続き各パスに表示されます。 通常の最終出力を復元するには、実験シンボルをコメント アウトしてください。

Summary

各手法は、同じタスクの異なる部分に対応します。

  • ラムダと LINQ は、並べ替えと合計のために、名前とコピー数をインラインで選択します。
  • 反復子は、カスタムの一対多の生成を表し、ラベルの消費を呼び出し元に委ねます。
  • Aswitch式は、ロール固有の値を計算し、サポートされていないロールを明示します。
  • ローカル関数は 、書式設定ステップに名前を付け、そのスコープを制限し、入力を指定します。

スコープ、依存関係、実行順序が操作に適合する場合は、これらのフォームを選択します。 直接ループ処理、共有メソッド、または完成したコレクションは、他の呼び出し元に適しています。