foreach和传统的for循环使用C#中的List <t>

时间:2015-11-24 10:10:05

标签: c# c++ list foreach iterator

在C#中,我发现没有像C ++或Java的迭代器这样的东西。在C ++中,我被建议不要使用索引迭代链接列表,因为在每个循环中从第一个节点访问会对性能产生影响。但似乎我在C#中只有两个选择。传统 for-loop VS foreach

C#有什么不同?与C ++不同,for循环没有性能问题?

我也听说foreach在每次循环迭代中创建每个新变量,就像在Java中一样,所以我不知道哪一个适合低端手机。

2 个答案:

答案 0 :(得分:2)

这并没有完全回答你的问题,但仍然想指出这个假设是假的:

  

在C#中,我发现那里没有类似C ++或Java的迭代器

它在C#中称为枚举器,请参阅IEnumerator<T>

还要使用传统的for循环来考虑此代码示例:

static void Main(string[] args)
{
    var data = new List<int> { 7, 10, 0 };
    for (var it = data.GetEnumerator(); it.MoveNext(); )
    {
        Console.WriteLine(it.Current);
    }
}

无论如何,我认为没有人会在此示例中迭代列表或IEnumerable:)

答案 1 :(得分:2)

在C#中有一个迭代器的概念,它是IEnumerable<T>,它可以提供对集合的顺序访问。

List<T>LinkedList<T>都实现了这个接口,并且在两种情况下都没有与索引操作的算法复杂性相关的性能损失。

作为旁注,LinkedList<T>在.NET中没有快速追加操作的好处,因为List<T>在将项添加到列表末尾时具有O(1)摊销时间,并且List<T>对GC的压力较小,因为数据存储在需要时会以指数方式增长,所以最终大部分时间都会使用List<T>

至于List<T>和“同一变量”问题的索引访问的性能,我认为以下代码演示了使用场景。

在'相同变量'检查中,您可以看到,在'for'的情况下,变量在外部作用域中,而对于foreach,它在最近编译器版本中的迭代器块的内部作用域中(需要检查哪个版本改变了这个)。 这是非常重要的,如果你做一个闭包,代码演示它。

void Main()
{
    var n = 10000000;
    var list = Enumerable.Range(0, n).ToList();

    var array = list.ToArray();

    Test(TestForeach, list, "foreach - List");
    Test(TestFor, list, "for - List");

    Test(TestForeach, array, "foreach - Array");
    Test(TestFor, array, "for - Array");

    TestSameVariableFor();
    TestSameVariableForeach();
}

void TestSameVariableFor()
{
    var sum = 0;
    List<Action> actions = new List<Action>();
    for (var i = 0; i < 2; i++)
    {
        actions.Add(() => sum += i);
    }

    foreach (var a in actions)
    {
        a();
    }

    Console.WriteLine("For - Sum is {0}", sum);
}

void TestSameVariableForeach()
{
    var sum = 0;
    List<Action> actions = new List<Action>();
    foreach (var i in Enumerable.Range(0, 2))
    {
        actions.Add(() => sum += i);
    }

    foreach (var a in actions)
    {
        a();
    }

    Console.WriteLine("Foreach - Sum is {0}", sum);
}

void Test(Action<List<int>> action, List<int> list, string what)
{
    var sw = Stopwatch.StartNew();
    action(list);
    sw.Stop();
    Console.WriteLine("Elapsed {0}, {1}", sw.ElapsedMilliseconds, what);
    Console.WriteLine();
}

void Test(Action<int[]> action, int[] list, string what)
{
    var sw = Stopwatch.StartNew();
    action(list);
    sw.Stop();
    Console.WriteLine("Elapsed {0}, {1}", sw.ElapsedMilliseconds, what);
    Console.WriteLine();
}

void TestFor(List<int> list)
{
    long sum = 0;

    var count = list.Count;
    for (var i = 0; i < count; i++)
    {
        sum += i;
    }

    Console.WriteLine(sum);
}

void TestForeach(List<int> list)
{
    long sum = 0;

    foreach (var i in list)
    {
        sum += i;
    }

    Console.WriteLine(sum);
}

void TestFor(int[] list)
{
    long sum = 0;

    var count = list.Length;
    for (var i = 0; i < count; i++)
    {
        sum += i;
    }

    Console.WriteLine(sum);
}

void TestForeach(int[] list)
{
    long sum = 0;

    foreach (var i in list)
    {
        sum += i;
    }

    Console.WriteLine(sum);
}

输出:

49999995000000
Elapsed 37, foreach - List

49999995000000
Elapsed 6, for - List

49999995000000
Elapsed 7, foreach - Array

49999995000000
Elapsed 6, for - Array

For - Sum is 4
Foreach - Sum is 1

更新: 以下是描述foreach语义更改的帖子: Is there a reason for C#'s reuse of the variable in a foreach?