【问题标题】:foreach, performance-wise. Should we declare variable once before loop or inside it?foreach,性能方面。我们应该在循环之前还是在循环内部声明一次变量?
【发布时间】:2009-10-27 17:35:40
【问题描述】:

在 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;
        }

当然我在这里谈论项目对象。 谢谢大家。

【问题讨论】:

    标签: c# scope variable-assignment


    【解决方案1】:

    这听起来像premature optimization

    首先,你有理由相信这里存在性能问题吗?

    其次,在发布版本中,编译器的优化器可能会为两种情况生成相同的代码 - 所以它可能无关紧要。在调试版本中,这可能并不总是正确的,但您不希望进行优化,因为调试版本的目的是让您准确地单步执行代码。

    【讨论】:

      【解决方案2】:

      有一个非常重要的极端情况;如果您将变量“捕获”到匿名方法/lambda中。否则为时过早,没有任何区别。完全没有。

      一个重要的例子:

      // 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); });
      }
      

      【讨论】:

        【解决方案3】:

        我很确定您的两个代码块生成的 IL 是相同的。性能应该没有任何变化。但是,您在使用它的地方声明项目类型的第二个代码块更具可读性,我会使用它。

        【讨论】:

          【解决方案4】:

          这是一个非常微小的优化,如果不生成相同的代码,这两种方法在性能方面可能完全相同。在这种情况下,请考虑可读性。我更喜欢第二个,因为您的对象在 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 };
          
            foreach (var i in collection)
            {
              items.Add(new ListItem { Text = i.ToString() });
            }
          
            return items;
          }
          

          【讨论】:

          • 这通常是我所做的。这是自助服务,所以我会支持你:D
          【解决方案5】:

          这两个块创建的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;
              }
          

          【讨论】:

            【解决方案6】:

            可能会编译为相同的代码,但为什么还要重新声明它。 这是参考的好处,在这种情况下是项目。 完成后,您可以将其分配给另一个 ListItem 和 GC 照顾其余的。

            但另一方面,其他程序员的可读性。这个决定肯定不会显着改变您的应用程序性能。

            【讨论】:

              【解决方案7】:

              在你的情况下更好的是:

              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;        
              }
              

              为什么要创建一个额外的变量?

              【讨论】:

                【解决方案8】:

                正如大家所猜测的,IL 将是相同的。此外,正如其他人所提到的,在它们成为问题之前不要担心这样的事情。相反,问问自己该变量的范围属于哪里。

                该代码块的范围和上下文比微小的性能优化重要得多,在这种情况下,这种优化本质上是不成熟的并且是不必要的。

                【讨论】:

                  猜你喜欢
                  • 2014-03-24
                  • 1970-01-01
                  • 2015-04-12
                  • 2011-04-10
                  • 1970-01-01
                  • 2011-06-01
                  • 1970-01-01
                  • 2012-02-06
                  相关资源
                  最近更新 更多