在foreach循环内部或外部声明变量:哪个更快/更好?

时间:2009-12-10 23:39:39

标签: c# foreach

其中哪一个更快/更好?

这一个:

List<User> list = new List<User>();
User u;

foreach (string s in l)
{
    u = new User();
    u.Name = s;
    list.Add(u);
}

或者这个:

List<User> list = new List<User>();

foreach (string s in l)
{
    User u = new User();
    u.Name = s;
    list.Add(u);
}

我的新手开发技巧告诉我第一个更好,但我的一个朋友告诉我错了,但不能给我一个很好的理由为什么第二个更好。

性能有什么不同吗?

10 个答案:

答案 0 :(得分:96)

在性能方面,两个示例都编译为相同的IL,因此没有区别。

第二个更好,因为如果u仅在循环中使用,它会更清楚地表达你的意图。

答案 1 :(得分:14)

在任何情况下,最好的方法是使用一个带有Name的构造函数...或者,否则,使用大括号表示法:

foreach (string s in l)
{
    list.Add(new User(s));
}

foreach (string s in l)
{
    list.Add(new User() { Name = s });
}

甚至更好,LINQ:

var list = l.Select( s => new User { Name = s});

现在,虽然你的第一个例子在某些情况下可能会在不知不觉中更快,但第二个例子更好,因为它更具可读性,编译器可能会丢弃变量(并完全省略它),因为它不会在{{{ 1}}的范围。

答案 2 :(得分:6)

声明不会导致任何代码被执行,因此这不是性能问题。

第二个是你的意思,如果你是第二种方式,你不太可能犯一个愚蠢的错误,所以使用它。始终尝试在必要的最小范围内声明变量。

此外,更好的方法是使用Linq:

List<User> users = l.Select(name => new User{ Name = name }).ToList();

答案 3 :(得分:5)

每当你对性能提出疑问时,唯一要做的就是测量 - 围绕测试运行循环并计时。

要回答你的问题 - 不测量:-)或者查看生成的ilasm - 任何差异在有意义的迭代次数中都不会引人注意,并且代码中最昂贵的操作可能是用户分配几个数量级,所以专注于代码清晰度(正如你应该的那样)和2。

哦,已经很晚了,我想我只是想说不要担心这类事情,或者陷入这样的细节。

ķ

答案 4 :(得分:1)

第二个更好。您的意思是在每次迭代中都有一个新用户。

答案 5 :(得分:1)

从技术上讲,第一个示例将节省几纳秒,因为不必移动堆栈帧来分配新变量,但这是一个很小的CPU时间你不会注意到它,如果是编译器并没有优化任何差异。

答案 6 :(得分:1)

在这种情况下,第二个版本更好。

通常,如果只需要访问迭代体内的值,则选择第二个版本。另一方面,如果有一些最终状态,变量将保持在循环体之外,然后声明然后使用第一个版本。

答案 7 :(得分:0)

表现应该没有令人难以置信的差异。

答案 8 :(得分:0)

答案 9 :(得分:0)

我去验证了这个问题。

(?:<[^>]+>)?

CIL泄漏出只有变量获得不同的编号。

See this in action here

所以我准备了一些本来应该更好的东西。

namespace Test
{
  class Foreach
  {
    string[] names = new[] { "ABC", "MNL", "XYZ" };

    void Method1()
    {
      List<User> list = new List<User>();
      User u;

      foreach (string s in names)
      {
        u = new User();
        u.Name = s;
        list.Add(u);
      }
    }

    void Method2()
    {

      List<User> list = new List<User>();

      foreach (string s in names)
      {
        User u = new User();
        u.Name = s;
        list.Add(u);
      }
    }
  }

  public class User { public string Name; }
}

CIL没有区别。

enter image description here

正如已经指出的那样,声明不是分配的,因此不存在性能损失。

测试

namespace Test
{
  class Loop
  { 

    public TimeSpan method1 = new TimeSpan();
    public TimeSpan method2 = new TimeSpan();

    Stopwatch sw = new Stopwatch();

    public void Method1()
    {
      sw.Restart();

      C c;
      C c1;
      C c2;
      C c3;
      C c4;

      int i = 1000;
      while (i-- > 0)
      {
        c = new C();
        c1 = new C();
        c2 = new C();
        c3 = new C();
        c4 = new C();        
      }

      sw.Stop();
      method1 = method1.Add(sw.Elapsed);
    }

    public void Method2()
    {
      sw.Restart();

      int i = 1000;
      while (i-- > 0)
      {
        var c = new C();
        var c1 = new C();
        var c2 = new C();
        var c3 = new C();
        var c4 = new C();
      }

      sw.Stop();
      method2 = method2.Add(sw.Elapsed);
    }
  }

  class C { }
}