4

我有一个像这样的代码:

        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) 2 3 4 我在 List 和 Collection 上测试了它,他们做得对。我怎样才能达到我所需要的?

4

2 回答 2

9

You can't because you have made your code surface a single enumerator, itself a mistake IMO. A better version would be, for me:

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

The compiler will create the right devices to achieve this with separate enumerators.

Unless you are writing for .NET 1.1, then if you find yourself manually writing an enumarator, there's a very good chance that you are doing it the hard way, and getting it wrong as a bonus.

If you really must do it the hard way:

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; }
    } 
}

The significance here is that different instances of TEnumerator allow the same T instance to be iterated separately.

于 2011-10-05T08:18:50.830 回答
5
foreach (int i in t)
   if (i == 2)
     foreach (int p in t)
       //print p
   else
       //print i

First always use braces, while you indenting matches what will happen another if in there will confuse things.

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

But you problem: you only have one counter per instance of T, and you are using the same instance. Therefore you do through once. If you want to allow concurrent enumerations the enumerator object will need to be separate with GetEnumerator returning a new instance each time.

于 2011-10-05T08:21:00.330 回答