如何为多个foreach实现正确的IEnumerator接口

本文关键字:IEnumerator 接口 实现 foreach | 更新日期: 2023-09-27 18:10:24

我有一个类似于的代码

        class T : IEnumerable, IEnumerator
        {
            private int position = -1;
            public T() { }
            public IEnumerator GetEnumerator() { return this; }
            public object Current { get { return position; } }
            public bool MoveNext()
            {
                position++;
                return (position < 5);
            }
            public void Reset() { position = -1; }
        }
//Using in code:
T t = new T();
foreach (int i in t)
 //to do something

在上面的代码中,一切都很好,但当我使用下一个:

foreach (int i in t)
   if (i == 2)
     foreach (int p in t)
       //print p
   else
       //print i

它打印(在括号中的第二个循环(:0 1(3 4(2而不是0 1(0 1 2 3 4(我在List和Collection上测试了它,他们做得很好。我怎样才能得到我需要的?

如何为多个foreach实现正确的IEnumerator接口

你不能这样做,因为你把代码表面变成了一个枚举器,这本身就是一个错误。对我来说,更好的版本是:

class T : IEnumerable<int> {
    public IEnumerator<int> GetEnumerator() {
        int i = 0;
        while(i < 5) {
            yield return i;
            i++;
        }
    }
    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

编译器将创建合适的设备,通过单独的枚举器来实现这一点。

除非你是为.NET 1.1编写的,否则如果你发现自己手动编写枚举器,那么很有可能你做得很艰难,而且会出错。

如果你真的必须用困难的方法:

class T : IEnumerable<int>
{
    public T() { }
    public IEnumerator<int> GetEnumerator() { return new TEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
    private class TEnumerator : IEnumerator<int>
    {
        private int position = -1;
        public int Current { get { return position; } }
        object IEnumerator.Current { get { return Current; } }
        void IDisposable.Dispose() {}
        public bool MoveNext()
        {
            position++;
            return (position < 5);
        }
        public void Reset() { position = -1; }
    } 
}

这里的意义在于,TEnumerator的不同实例允许相同的T实例单独迭代。

foreach (int i in t)
   if (i == 2)
     foreach (int p in t)
       //print p
   else
       //print i

首先,总是使用大括号,当您缩进匹配时,其中的另一个if会混淆事情。

foreach (int i in t) {
   if (i == 2) {
     foreach (int p in t) {
       //print p
      }
   } else {
       //print i
   }
 }

但您的问题是:T的每个实例只有一个计数器,并且您使用的是同一个实例。所以你只做一次。如果要允许并发枚举,则需要将枚举器对象分开,GetEnumerator每次都返回一个新实例。