foreach和带有List<;T>;在C#中

本文关键字:gt lt List foreach | 更新日期: 2023-09-27 18:24:16

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

它在C#中不同吗?与C++不同,for循环没有性能问题?

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

foreach和带有List<;T>;在C#中

这并不能完全回答你的问题,但仍然想指出这个假设是错误的:

在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:)

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语义变化的帖子:C#';s重用foreach中的变量?