我什么时候应该使用IEnumerator在c#中进行循环?

lomaxx 24 c# ienumerable iterator loops

我想知道是否有时候在foreach循环中使用IEnumerator来迭代集合是否有利?例如,有没有时间使用以下代码示例中的任何一个而不是另一个?

IEnumerator<MyClass> classesEnum = myClasses.GetEnumerator();
while(classesEnum.MoveNext())
    Console.WriteLine(classesEnum.Current);

代替

foreach (var class in myClasses)
    Console.WriteLine(class);

Marc Gravell.. 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            
}


Jay Bazuzi.. 19

根据C#语言规范:

表格的foreach声明

foreach (V v in x) embedded-statement

然后扩展到:

{
    E e = ((C)(x)).GetEnumerator();
    try {
            V v;
            while (e.MoveNext()) {
                    v = (V)(T)e.Current;
                    embedded-statement
            }
    }
    finally {
            ... // Dispose e
    }
}

你的两个例子的本质是相同的,但有一些重要的区别,最值得注意的是try/ finally.


Andy.. 12

在C#中,foreachIEnumerator上面发布的代码完全相同.foreach提供该构造以使程序员更容易.我相信在两种情况下产生的IL都是相同/相似的.

  • 实际上,没有IL在他的样本中**不相同,因为他没有检查IDisposable的迭代器.这对许多迭代器很重要. (3认同)