6

foreachステートメントの外側で変数を宣言し、そのたびに変数をその側に再割り当てする(foreach)か、foreach内に新しい変数を作成するなど、パフォーマンスの面で優れている点

private List<ListItem> GetItems()
        {
            var items = new List<ListItem>();
            var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            ListItem item;
            foreach (var i in collection)
            {
                item = new ListItem { Text = i.ToString() };
                items.Add(item);
            }

            return items;
        }

またはこれ?

private List<ListItem> GetItems()
        {
            var items = new List<ListItem>();
            var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            foreach (var i in collection)
            {
                ListItem item = new ListItem { Text = i.ToString() };
                items.Add(item);
            }

            return items;
        }

確かにここで私はアイテムオブジェクトについて話している。皆さん、ありがとうございました。

4

8 に答える 8

12

これは時期尚早の最適化のように聞こえます。

まず、ここにパフォーマンスの問題があると信じる理由はありますか?

第2に、リリースビルドでは、コンパイラのオプティマイザはおそらく両方のシナリオで同じコードを生成するため、無関係である可能性があります。デバッグビルドでは、これが常に当てはまるとは限りませんが、デバッグビルドの目的はコードを正確にステップ実行できるようにすることであるため、最適化は必要ありません。

于 2009-10-27T17:39:17.417 に答える
7

これ重要なエッジケースがあります。変数を匿名メソッド/ラムダに「キャプチャ」する場合。そうでなければ、時期尚早であり、違いはありません。まったく。

重要な場合の例:

// prints all items in no particular order
foreach (var i in collection)
{
    string s = i.ToString();
    ThreadPool.QueueUserWorkItem(delegate { Console.WriteLine(s); });
}

// may print the same item each time, or any combination of items; very bad
string s;
foreach (var i in collection)
{
    s = i.ToString();
    ThreadPool.QueueUserWorkItem(delegate { Console.WriteLine(s); });
}
于 2009-10-27T17:58:40.860 に答える
4

2つのコードブロックによって生成されたILは同じであると確信しています。パフォーマンスに変化はないはずです。ただし、アイテムのタイプを使用場所で宣言する2番目のコードブロックは、少し読みやすく、それを使用します。

于 2009-10-27T17:39:16.950 に答える
3

これは非常にマイクロ最適化であり、同じコードを生成しない場合、両方の方法はパフォーマンス的にまったく同じになる可能性があります。この場合、読みやすさを重視してください。あなたのオブジェクトはforeachループの外では何の役にも立たないので、私は2番目を好みます。

間違いなく、保存されている参照をまとめて削除することもできます。

private List<ListItem> GetItems()
{
  var items = new List<ListItem>();
  var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

  foreach (var i in collection)
  {
    items.Add(new ListItem { Text = i.ToString() });
  }

  return items;
}
于 2009-10-27T17:39:33.783 に答える
1

2つのブロックによって作成されるILはほぼ同じである必要があります。最適化を検討している場合は、アイテムを入力する前に、最終リストの長さを設定することを検討します。そうすれば、リストの長さを拡張することによる拡張ペナルティにはなりません。

何かのようなもの:

  private List<ListItem> GetItems()
    {
        var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        var items = new List<ListItem>(collection.Count);  //declare the amount of space here

        foreach (var i in collection)
        {
            ListItem item = new ListItem { Text = i.ToString() };
            items.Add(item);
        }

        return items;
    }
于 2009-10-27T17:41:38.493 に答える
0

おそらく同じコードにコンパイルされますが、なぜわざわざ再宣言するのですか。これは、参照、この場合はアイテムの良いところです。完了したら、それを別のListItemに割り当てることができ、残りはGCが処理します。

しかし一方で、他のプログラマーにとっては読みやすさです。これは、アプリケーションのパフォーマンスを大幅に変更しないという決定です。

于 2009-10-27T17:40:03.690 に答える
0

あなたの場合はさらに良いです:

private List<ListItem> GetItems()        
{            
   var items = new List<ListItem>();            
   var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };            
   foreach (var i in collection)            
      items.Add(new ListItem { Text = i.ToString() });                 
   return items;        
}

なぜ余分な変数を作成するのですか?

于 2009-10-27T17:40:33.687 に答える
0

誰もが推測したように、IL は同一になります。また、他の方もおっしゃっているように、このようなことは問題になるまで気にしないでください。代わりに、その変数のスコープがどこに属しているかを自問してください。

そのコード ブロックのスコープとコンテキストは、このシナリオでは時期尚早で不要な小さなパフォーマンスの最適化よりもはるかに重要です。

于 2009-10-27T17:49:25.820 に答える