迭代强类型genericsList 的最佳方法是什么?

在C#.NET和VB.NET中迭代强类型genericsList的最佳方法是什么?

对于C#:

foreach(ObjectType objectItem in objectTypeList) { // ...do some stuff } 

Purple Ant回答VB.NET:

 For Each objectItem as ObjectType in objectTypeList 'Do some stuff ' Next 

使用IEnumerable的任何通用实现,最好的方法是:

 //C# foreach( var item in listVariable) { //do stuff } 

但是有一个重要的例外。 IEnumerable涉及Current()和MoveNext()的开销,这是foreach循环实际编译成的。

当你有一个简单的结构数组:

 //C# int[] valueTypeArray; for(int i=0; i < valueTypeArray.Length; ++i) { int item = valueTypeArray[i]; //do stuff } 

更快。


更新

在与@Steven Sudit讨论之后(见评论)我认为我的原始建议可能已经过时或有误,所以我进行了一些测试:

 // create a list to test with var theList = Enumerable.Range(0, 100000000).ToList(); // time foreach var sw = Stopwatch.StartNew(); foreach (var item in theList) { int inLoop = item; } Console.WriteLine("list foreach: " + sw.Elapsed.ToString()); sw.Reset(); sw.Start(); // time for int cnt = theList.Count; for (int i = 0; i < cnt; i++) { int inLoop = theList[i]; } Console.WriteLine("list for : " + sw.Elapsed.ToString()); // now run the same tests, but with an array var theArray = theList.ToArray(); sw.Reset(); sw.Start(); foreach (var item in theArray) { int inLoop = item; } Console.WriteLine("array foreach: " + sw.Elapsed.ToString()); sw.Reset(); sw.Start(); // time for cnt = theArray.Length; for (int i = 0; i < cnt; i++) { int inLoop = theArray[i]; } Console.WriteLine("array for : " + sw.Elapsed.ToString()); Console.ReadKey(); 

所以,我在发布时运行了所有优化:

 list foreach: 00:00:00.5137506 list for : 00:00:00.2417709 array foreach: 00:00:00.1085653 array for : 00:00:00.0954890 

然后调试没有优化:

 list foreach: 00:00:01.1289015 list for : 00:00:00.9945345 array foreach: 00:00:00.6405422 array for : 00:00:00.4913245 

所以看起来相当一致, for它比foreach更快,并且数组比通用列表更快。

然而,这是100,000,000次迭代,差异大约是最快和最慢方法之间的.4秒。 除非你正在进行大规模的性能关​​键循环,否则不值得担心。

对于VB.NET:

 For Each tmpObject as ObjectType in ObjectTypeList 'Do some stuff ' Next 

C#

 myList().ForEach( delegate(string name) { Console.WriteLine(name); }); 

匿名委托目前尚未在VB.Net中实现,但C#和VB.Net都应该能够执行lambdas:

C#

 myList().ForEach(name => Console.WriteLine(name)); 

VB.Net

 myList(Of String)().ForEach(Function(name) Console.WriteLine(name)) 

正如Grauenwolf指出的那样,上面的VB不会编译,因为lambda没有返回值。 正如其他人所建议的那样,正常的ForEach循环现在可能是最简单的,但是像往常一样,需要一段代码来完成C#在一行中可以做的事情。


下面是为什么这可能有用的一个典型示例:这使您能够从IEnumerable存在的另一个范围传递循环逻辑,因此如果您不想要,甚至不必公开它。

假设您有一个绝对的相对URL路径列表:

 public IEnumerable Paths(Func formatter) { List paths = new List() { "/about", "/contact", "/services" }; return paths.ForEach(formatter); } 

那么你可以这样调用函数:

 var hostname = "myhost.com"; var formatter = f => String.Format("http://{0}{1}", hostname, f); IEnumerable absolutePaths = Paths(formatter); 

给你"http://myhost.com/about", "http://myhost.com/contact"等。显然有更好的方法来完成这个特定的例子,我只是想certificate基本原理。

在不知道列表的内部实现的情况下,我认为通常迭代它的最佳方法是foreach循环。 因为foreach使用IEnumerator遍历列表,所以由列表本身决定如何从一个对象移动到另一个对象。

如果内部实现是一个链表,那么一个简单的for循环将比foreach慢得多。

那有意义吗?

这取决于您的应用:

  • for loop,如果效率是优先考虑的话
  • foreach循环或ForEach方法,无论哪个更清楚地传达您的意图

我可能会遗漏一些东西,但如果您使用下面的示例,则迭代通用列表应该相当简单。 List <>类实现IList和IEnumerable接口,以便您可以基本上以任何方式轻松迭代它们。

最有效的方法是使用for循环:

 for(int i = 0; i < genericList.Count; ++i) { // Loop body } 

您也可以选择使用foreach循环:

 foreach( o in genericList) { // Loop body }