lom*_*axx 24 c# ienumerable iterator loops
我想知道是否有时候在foreach循环中使用IEnumerator来迭代集合是否有利?例如,有没有时间使用以下代码示例中的任何一个而不是另一个?
IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator();
while(classesEnum.MoveNext())
Console.WriteLine(classesEnum.Current);
Run Code Online (Sandbox Code Playgroud)
代替
foreach (var class in myClasses)
Console.WriteLine(class);
Run Code Online (Sandbox Code Playgroud)
Mar*_*ell 31
首先,请注意您的示例(在foreach和之间GetEnumerator)的一个重大区别是,如果迭代器是,则foreach保证调用Dispose()迭代器IDisposable.这对于许多迭代器(例如,可能正在消耗外部数据馈送)很重要.
实际上,有些情况foreach并不像我们想的那样有用.
首先,这里讨论了"第一项"案例(foreach /检测第一次迭代).
还有一点; 如果你尝试编写丢失的Zip方法将两个可枚举的序列拼接在一起(或SequenceEqual方法),你会发现你可以'使用foreach两个序列,因为那将执行交叉连接.您需要直接为其中一个使用迭代器:
static IEnumerable<T> Zip<T>(this IEnumerable<T> left,
IEnumerable<T> right)
{
using (var iter = right.GetEnumerator())
{
// consume everything in the first sequence
foreach (var item in left)
{
yield return item;
// and add an item from the second sequnce each time (if we can)
if (iter.MoveNext())
{
yield return iter.Current;
}
}
// any remaining items in the second sequence
while (iter.MoveNext())
{
yield return iter.Current;
}
}
}
static bool SequenceEqual<T>(this IEnumerable<T> left,
IEnumerable<T> right)
{
var comparer = EqualityComparer<T>.Default;
using (var iter = right.GetEnumerator())
{
foreach (var item in left)
{
if (!iter.MoveNext()) return false; // first is longer
if (!comparer.Equals(item, iter.Current))
return false; // item different
}
if (iter.MoveNext()) return false; // second is longer
}
return true; // same length, all equal
}
Run Code Online (Sandbox Code Playgroud)
Jay*_*uzi 19
根据C#语言规范:
表格的foreach声明
foreach (V v in x) embedded-statement
Run Code Online (Sandbox Code Playgroud)
然后扩展到:
{
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
... // Dispose e
}
}
Run Code Online (Sandbox Code Playgroud)
你的两个例子的本质是相同的,但有一些重要的区别,最值得注意的是try/ finally.
And*_*ndy 12
在C#中,foreach与IEnumerator上面发布的代码完全相同.foreach提供该构造以使程序员更容易.我相信在两种情况下产生的IL都是相同/相似的.