17

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

4

7 回答 7

32

对于 C#:

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

Purple Ant对 VB.NET 的回答:

For Each objectItem as ObjectType in objectTypeList
    'Do some stuff '
Next
于 2008-08-18T20:52:25.980 回答
21

对于 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 次迭代,最快和最慢方法之间的差异约为 0.4 秒。除非您正在执行大规模的性能关​​键循环,否则不值得担心。

于 2008-08-18T21:18:00.187 回答
5

C#

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

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

C#

myList<string>().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<String> Paths(Func<String> formatter) {
    List<String> paths = new List<String>()
    {
        "/about", "/contact", "/services"
    };

    return paths.ForEach(formatter);
}

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

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

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

于 2008-08-18T21:21:49.337 回答
4

对于 VB.NET:

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

于 2008-08-18T21:01:07.850 回答
2

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

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

那有意义吗?

于 2008-08-18T21:06:49.383 回答
2

这取决于您的应用程序:

  • for 循环,如果效率是优先级
  • foreach 循环或 ForEach 方法,以更清楚地传达您的意图为准
于 2008-08-19T02:01:14.203 回答
1

我可能遗漏了一些东西,但是如果您使用下面的示例,遍历通用列表应该相当简单。List<> 类实现了 IList 和 IEnumerable 接口,因此您可以轻松地以任何您想要的方式遍历它们。

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

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

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

foreach(<insertTypeHere> o in genericList)
{
    // Loop body
}
于 2008-08-18T20:54:56.630 回答