开发者

How to know if an enumerator has reached the end of the collection in C#?

I am porting a library from C++ to C#. The old library uses vectors from C++ and in the C# I am using gene开发者_高级运维ric Dictionaries because they're actually a good data structure for what I'm doing (each element has an ID, then I just use using TypeDictionary = Dictionary<String, Type>;). Now, in the C# code I use a loop like this one

TypeDictionary.Enumerator tdEnum = MyTypeDictionary.GetEnumerator();

while( tdEnum.MoveNext() ) 
{
   Type element = typeElement.Current.Value;

   // More code here
}

to iterate through the elements of the collection. The problem is that in particular cases I need to check if a certain enumerator has reached the end of the collection, in C++ I would have done a check like this:

if ( tdEnum == MyTypeDictionary.end() ) // More code here

But I just don't know how to handle this situation in C#, any ideas?

Thank you

Tommaso


Here's a pretty simple way of accomplishing this.

bool hasNext = tdEnum.MoveNext();
while (hasNext) {
    int i = tdEnum.Current;
    hasNext = tdEnum.MoveNext();
}

I found an online tutorial that also may help you understand how this works.

http://www.c-sharpcorner.com/UploadFile/prasadh/Enumerators11132005232321PM/Enumerators.aspx


You know that you're at the end of an iterator when MoveNext() returns false. Otherwise you need to upgrade to a more descriptive data structure like IList<T>.


I have a "smart iterator" class in MiscUtil which you may find useful. It lets you test whether you're currently looking at the start or end of the sequence, and the index within the sequence. See the usage page for more information.

Of course in most cases you can just get away with doing this manually using the result of MoveNext(), but occasionally the extra encapsulation comes in handy.

Note that by necessity, this iterator will always have actually consumed one more value than it's yielded, in order to know whether or not it's reached the end. In most cases that isn't an issue, but it could occasionally give some odd experiences when debugging.


Using the decorator pattern to hold a value if the enumerator has ended is a valid approach. Since it implements IEnumerator, you won't find difficulties to replace it in your code.

Here's a test class:

using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MyDictionary = System.Collections.Generic.Dictionary<int, string>;
using MyKeyValue = System.Collections.Generic.KeyValuePair<int, string>;

namespace TestEnumerator
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestingMyEnumeradorPlus()
        {
            var itens = new MyDictionary()
            {
                { 1, "aaa" }, 
                { 2, "bbb" }
            };
            var enumerator = new EnumeradorPlus<MyKeyValue>(itens.GetEnumerator());
            enumerator.MoveNext();
            Assert.IsFalse(enumerator.Ended);
            enumerator.MoveNext();
            Assert.IsFalse(enumerator.Ended);
            enumerator.MoveNext();
            Assert.IsTrue(enumerator.Ended);
        }
    }

    public class EnumeradorPlus<T> : IEnumerator<T>
    {
        private IEnumerator<T> _internal;
        private bool _hasEnded = false;

        public EnumeradorPlus(IEnumerator<T> enumerator)
        {
            _internal = enumerator;
        }

        public T Current
        {
            get { return _internal.Current; }
        }

        public void Dispose()
        {
            _internal.Dispose();
        }

        object System.Collections.IEnumerator.Current
        {
            get { return _internal.Current; }
        }

        public bool MoveNext()
        {
            bool moved = _internal.MoveNext();
            if (!moved)
                _hasEnded = true;
            return moved;
        }

        public void Reset()
        {
            _internal.Reset();
            _hasEnded = false;
        }

        public bool Ended
        {
            get { return _hasEnded; }
        }
    }
}


Coming from C++ you might not be up to date on C# syntax. Perhaps you could simply use the foreach construct to avoid the test all together. The following code will be executed once for each element in your dictionary:

foreach (var element in MyTypeDictionary)
{
    // More code here
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜