C# 在 foreach 循环内部或外部声明变量:哪个更快/更好?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1884906/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Declaring a variable inside or outside an foreach loop: which is faster/better?
提问by Marcus
Which one of these is the faster/better one?
其中哪一个是更快/更好的?
This one:
这个:
List<User> list = new List<User>();
User u;
foreach (string s in l)
{
u = new User();
u.Name = s;
list.Add(u);
}
Or this one:
或者这个:
List<User> list = new List<User>();
foreach (string s in l)
{
User u = new User();
u.Name = s;
list.Add(u);
}
My newbie-developing skills tells me the first one is better, but a friend of mine tells me im wrong, but could not give me a good reason why the second one is better.
我的新手开发技能告诉我第一个更好,但我的一个朋友告诉我我错了,但无法给我一个很好的理由为什么第二个更好。
Is there any difference in performance at all?
性能上有什么区别吗?
采纳答案by dtb
Performance-wise both examples are compiled to the same IL, so there's no difference.
在性能方面,两个示例都编译为相同的 IL,因此没有区别。
The second is better, because it more clearly expresses your intent if u
is only used inside the loop.
第二个更好,因为如果u
仅在循环内使用,它会更清楚地表达您的意图。
回答by Jarrett Widman
The 2nd one is better. You are meaning to have a new user in each iteration.
第2个更好。您的意思是在每次迭代中都有一个新用户。
回答by Jacob Adams
There should be no percievable difference in performance.
性能上应该没有明显的差异。
回答by Erik Funkenbusch
Technically, the first example will save a few nanoseconds because the stack frame will not have to be moved to allocate a new variable, but this is such a tiny amount of CPU time you won't notice it, that's if the compiler doesn't optimize any difference away anyays.
从技术上讲,第一个示例将节省几纳秒,因为不必移动堆栈帧来分配新变量,但这是极少量的 CPU 时间,您不会注意到它,如果编译器没有优化任何差异。
回答by Mark Byers
A declaration does not cause any code to be executed, so it's not a performance issue.
声明不会导致执行任何代码,因此它不是性能问题。
The second one is what you mean, and you're less likely to make a stupid error if you do it the second way, so use that. Always try to declare variables in the smallest scope necessary.
第二个就是你的意思,如果你用第二种方式来做,你不太可能犯愚蠢的错误,所以使用它。始终尝试在必要的最小范围内声明变量。
And besides, the better way is to use Linq:
此外,更好的方法是使用 Linq:
List<User> users = l.Select(name => new User{ Name = name }).ToList();
回答by csj
In this scenario, the second version is better.
在这种情况下,第二个版本更好。
In general, if you only need to access the value within the body of the iteration, then choose the second version. On the other hand, if there is some final state the variable will hold beyond the body of the loop, then declare then use the first version.
一般来说,如果只需要访问迭代体内部的值,那么选择第二个版本。另一方面,如果有一些最终状态变量将保持在循环体之外,然后声明然后使用第一个版本。
回答by Tordek
In any case, the best way would be to use a constructor that takes a Name... or, otherwise, exploit curly-brace notation:
在任何情况下,最好的方法是使用带有 Name... 的构造函数,否则,利用花括号表示法:
foreach (string s in l)
{
list.Add(new User(s));
}
or
或者
foreach (string s in l)
{
list.Add(new User() { Name = s });
}
or even better, LINQ:
甚至更好的是,LINQ:
var list = l.Select( s => new User { Name = s});
Now, while your first example could, in some cases, be unperceptibly faster, the second one is better because it's more readable, and the compiler may discard the variable (and omit it altogether) since it's not used outsid the foreach
's scope.
现在,虽然您的第一个示例在某些情况下可能快得难以察觉,但第二个示例更好,因为它更具可读性,并且编译器可能会丢弃该变量(并完全省略它),因为它没有在foreach
的范围之外使用。
回答by Kevin Shea
Whenever you've a question about performance, the only thing to do is measure - run a loop around your test and time it.
每当您对性能有疑问时,唯一要做的就是测量 - 围绕您的测试运行一个循环并计时。
To answer your question - without measuring :-) or looking at the generated ilasm - any difference wouldn't be noticeable in a meaningful number of iterations and the most expensive operation in your code there is likely to be the user allocation by a few orders of magnitude, so concentrate on code clarity (as you should in general) and go with 2.
要回答您的问题 - 不测量 :-) 或查看生成的 ilasm - 在有意义的迭代次数和代码中最昂贵的操作中,任何差异都不会引起注意,用户分配可能是几个订单量级,所以专注于代码清晰度(正如你通常应该的那样)并使用 2。
Oh, its late and I guess I'm just trying to say don't worry about this sort of thing or get caught up in details like this.
哦,太晚了,我想我只是想说不要担心这类事情或陷入这样的细节。
K
钾
回答by Sunil
Another reference which looks like above:
另一个参考,如上所示:
回答by Ucho
I went to verify this issue. Suprisingly finding out at my dirty tests that the 2nd option is even slightly faster all the time.
我去验证这个问题。令人惊讶的是,在我的脏测试中发现,第二个选项一直都稍微快一点。
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; }
}
I verified the CIL but it is not identical.
我验证了 CIL,但它不完全相同。
So I prepared something what I wanted to be much better test.
所以我准备了一些我想要更好的测试。
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 { }
}
Also in this case 2nd method was always winning but then I verified the CIL finding no difference.
同样在这种情况下,第二种方法总是获胜,但后来我验证了 CIL 发现没有区别。
I am not CIL-reading guru but I see no decleration issue. As was already pointed out declaration is not allocation so there is no performance penalty on it.
我不是 CIL 阅读大师,但我看不到 decleration 问题。正如已经指出的那样,声明不是分配,因此没有性能损失。
Test
测试
namespace Test
{
class Foreach
{
string[] names = new[] { "ABC", "MNL", "XYZ" };
public TimeSpan method1 = new TimeSpan();
public TimeSpan method2 = new TimeSpan();
Stopwatch sw = new Stopwatch();
void Method1()
{
sw.Restart();
List<User> list = new List<User>();
User u;
foreach (string s in names)
{
u = new User();
u.Name = s;
list.Add(u);
}
sw.Stop();
method1 = method1.Add(sw.Elapsed);
}
void Method2()
{
sw.Restart();
List<User> list = new List<User>();
foreach (string s in names)
{
User u = new User();
u.Name = s;
list.Add(u);
}
sw.Stop();
method2 = method2.Add(sw.Elapsed);
}
}
public class User { public string Name; }