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

这听起来像是过早的优化

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

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

于 2009-10-27T17:39:17.417 回答
7

有一个重要的极端情况。如果您将变量“捕获”到匿名方法/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); });
}
于 2009-10-27T17:58:40.860 回答
4

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

于 2009-10-27T17:39:16.950 回答
3

这是一个非常微小的优化,如果不生成相同的代码,两种方法在性能方面可能完全相同。在这种情况下,请考虑可读性。我更喜欢第二个,因为您的对象在 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;
}
于 2009-10-27T17:39:33.783 回答
1

这两个块创建的 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 回答