foreach,表现明智。我们应该在循环之前或里面声明变量吗?

时间:2009-10-27 17:35:40

标签: c# scope variable-assignment

对于性能明智而言,在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;
        }

肯定在这里我说的是物品对象。 谢谢大家。

8 个答案:

答案 0 :(得分:12)

这听起来像premature optimization

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

其次,在发布版本中,编译器的优化器可能会为两种情况生成相同的代码 - 因此它可能无关紧要。在调试版本中,这可能并非总是如此,但是您不需要进行优化,因为调试版本的目的是允许您准确地逐步执行代码。

答案 1 :(得分:7)

是一个重要的边缘案例;如果你将变量“捕获”到一个匿名方法/ lambda中。否则它是不成熟的,没有任何区别。完全没有。

何时重要的一个例子:

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

VS

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

答案 2 :(得分:4)

我很确定你的两个代码块生成的IL是相同的。表现不应有任何改变。但是,您在其中使用项目类型的第二个代码块稍微更具可读性,我会使用它。

答案 3 :(得分: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;
}

答案 4 :(得分: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;
    }

答案 5 :(得分:0)

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

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

答案 6 :(得分: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;        
}

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

答案 7 :(得分:0)

正如大家所推测的那样,IL将是相同的。另外,正如其他人所提到的那样,在问题出现之前不要担心这样的事情。相反,问问自己该变量的范围在哪里。

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