3

私は、データをループして、設定に基づいて特定の方法でフォーマットしているシナリオにいます。スタイル的に最適だと思うものがパフォーマンスを妨げる可能性があることを懸念しています。

コードの基本的なパターンは次のとおりです。

enum setting {single, multiple, foo, bar};
Data data = getData(Connection conn, int id);
setting blah = data.getSetting();
foreach (Item item in data)
{
   switch(blah)
   {
      case blah.single:
        processDataSingle(item blah);
        break;
      ...
   }
}

私の懸念は、データに何千、あるいは何万ものアイテムが存在する可能性があることです。繰り返し評価される可能性のあるループ内にスイッチがあると、重大なパフォーマンスの問題が発生する可能性があるのではないかと考えていました。switchループの前にを配置できることはわかっていますが、それぞれにループがcase含まれているため、基本的な機能が同じままであることがわかりにくいため、読みにくくなっています。

4

6 に答える 6

10

デリゲート/アクションを一度設定してから、ループ内で毎回呼び出すことができます。

Data data = getData(Connection conn, int id);
setting blah = data.getSetting();
Action<Item> doThis;
switch (blah)
{
  case blah.single:
      doThis = i => processSingleData(i blah);
      break;
  ...
}
foreach (Item item in data)
{
    doThis(item);
}

基本的に、各「ケース」の本体を に入れ、ループの外側でそれを選択し、ループで呼び出しActionます。ActionswitchAction

于 2013-02-28T15:36:08.377 に答える
2

可読性を維持するためのメソッドを作成してから、データをメソッドに渡すことができます。

void processAllData(IEnumerable<Item> data,  setting blah)
{
    switch(blah)
    {
      case blah.single:
        foreach (Item item in data)
        {

        }
    }
    // next case, next loop ...
}

次に、それは単なるワンライナーです:

processAllData(data, blah);

このアプローチは、複雑さをカプセル化するため読みやすく、見なければならないものだけを見るので簡潔であり、ケースを最適化できるので効率的です。

于 2013-02-28T15:38:57.620 に答える
1

このようにアクション デリゲートを使用することで、コードを大幅に因数分解できます。

enum setting {single, multiple, foo, bar};
Data data = getData(Connection conn, int id);

var processAll = new Action<Action<item>>(action =>
                    {
                        foreach(var item in data)                           
                            action(item);
                    });

setting blah = data.getSetting();

switch(blah)
{
    case blah.single:
       processAll(item => processDataSingle(item, blah));
       break;
       ...
}
于 2013-02-28T15:42:38.463 に答える
1

数万回以上の比較を実行する可能性について話している場合、パフォーマンスに影響を与える可能性は確かにあります。ここに記述したコードで発生する可能性があるもう 1 つの問題は、列挙型に追加する必要がある場合に発生することです。次に、このコードを開いて、その状況に対応するように調整する必要がありますが、これはOpen/Closed Principleに違反しています。

IMO が両方の問題を一度に解決する最善の方法は、Factory パターンを使用してこれを処理することです (それを開始する際のアドバイスについては、ここここの投稿を参照してください)。必要なのは、上記のスイッチ コードで呼び出したいメソッドを呼び出す実装を持つインターフェイスを用意することだけです。ファクトリを作成し、渡された列挙型に基づいて (ループの前に) コードに返す実装を選択します。その時点で、ループで行う必要があるのは、まさに必要なことを行うインターフェイス メソッドを呼び出すことだけです。

その後、将来の機能追加では、そのインターフェイスの別の実装を作成し、それに応じて列挙型を調整するだけで済みます。大騒ぎする必要はありません。

于 2013-02-28T15:42:44.470 に答える
0

そのようにスイッチをループに入れると、ほぼ確実に遅くなります。それが重要かどうかはわかりません。ストップウォッチを使用して確認してください。

于 2013-02-28T15:37:49.933 に答える
0

switch ステートメントの値が互いに近い場合、コンパイラは Nifステートメントの代わりにルックアップ テーブルを生成します。パフォーマンスは向上しますが、コンパイラがいつこれを行うかを判断するのは困難です。
代わりに、 を作成しDictionary<switchType,Delegate>、それに値とアクションのペアを入力してから、適切なアクションを選択すると、O(1)ディクショナリがハッシュ テーブルとして処理されます。
dictionary[value].Invoke().

于 2013-02-28T15:46:24.460 に答える