在c# / VB.NET/。哪个循环运行得更快,for还是foreach?

自从很久以前我读到for循环比foreach循环工作得快,我就认为它适用于所有集合、泛型集合、所有数组等。

我搜索了谷歌,找到了几篇文章,但大多数都是不确定的(阅读文章评论),而且是开放式的。

理想的情况是列出每种情况以及最佳解决方案。

例如(这只是一个例子):

用于迭代1000+的数组 字符串- for比foreach好 对于迭代IList(非泛型)字符串- foreach更好 比

在网上找到了一些相同的参考资料:

由Emmanuel Schanzer撰写的原创文章 CodeProject FOREACH Vs. FOR 博客——去博客还是不去博客,这是个问题 ASP。NET论坛- NET 1.1 c# for vs foreach

(编辑)

除了可读性之外,我对事实和数据真的很感兴趣。在某些应用中,最后一英里的性能优化确实很重要。


当前回答

你可以在Deep .NET - part 1迭代中读到它

它覆盖了从。net源代码一直到反汇编的结果(没有第一次初始化)。

数组迭代使用foreach循环:

And - list迭代foreach循环:

最终结果是:

其他回答

“有没有什么论据可以帮助我说服他使用for循环是可以接受的?”

不,如果你的老板事无巨细地告诉你应该使用哪种编程语言结构,你就真的没什么可说的了。对不起。

在大多数情况下,其实没有什么区别。

通常,当你没有显式的数值索引时,你总是必须使用foreach,而当你实际上没有可迭代集合时,你总是必须使用for(例如,在上三角形的二维数组网格上迭代)。在某些情况下,你可以做出选择。

有人可能会说,如果代码中开始出现神奇的数字,for循环可能会更难维护。你对不能使用for循环而不得不构建一个集合或使用lambda来构建子集合感到恼火应该是正确的,因为for循环已经被禁止了。

首先是对德米特里的回答(现已删除)的反诉。对于数组,c#编译器为foreach生成的代码与等效的For循环生成的代码大致相同。这就解释了为什么这个基准测试的结果基本相同:

using System;
using System.Diagnostics;
using System.Linq;

class Test
{
    const int Size = 1000000;
    const int Iterations = 10000;

    static void Main()
    {
        double[] data = new double[Size];
        Random rng = new Random();
        for (int i=0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }

        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j=0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop: {0}", sw.ElapsedMilliseconds);
    }
}

结果:

For loop: 16638
Foreach loop: 16529

接下来,验证Greg关于集合类型的观点是重要的——在上面将数组更改为List<double>,您将得到完全不同的结果。它不仅在一般情况下要慢得多,而且foreach也比通过索引访问慢得多。话虽如此,我仍然几乎总是喜欢foreach而不是for循环,因为它使代码更简单——因为可读性几乎总是重要的,而微优化很少是。

这可以节省你:

public IEnumerator<int> For(int start, int end, int step) {
    int n = start;
    while (n <= end) {
        yield n;
        n += step;
    }
}

Use:

foreach (int n in For(1, 200, 4)) {
    Console.WriteLine(n);
}

为了获得更大的胜利,你可以把三名代表作为参数。

请记住,for循环和foreach-循环并不总是等价的。如果列表更改,列表枚举器将抛出异常,但使用普通的for循环并不总是会得到该警告。如果列表在错误的时间更改,甚至可能会得到不同的异常。