在C#中,我发现没有像C ++或Java的迭代器这样的东西。在C ++中,我被建议不要使用索引迭代链接列表,因为在每个循环中从第一个节点访问会对性能产生影响。但似乎我在C#中只有两个选择。传统 for-loop VS foreach 。
C#有什么不同?与C ++不同,for循环没有性能问题?
我也听说foreach
在每次循环迭代中创建每个新变量,就像在Java中一样,所以我不知道哪一个适合低端手机。
答案 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?