Как узнать, достиг ли перечислитель конца коллекции в C #? - PullRequest
5 голосов
/ 26 апреля 2010

Я портирую библиотеку с C ++ на C #. Старая библиотека использует векторы из C ++, а в C # я использую общие словари, потому что они на самом деле являются хорошей структурой данных для того, что я делаю (у каждого элемента есть идентификатор, тогда я просто использую TypeDictionary = Dictionary<String, Type>;). Теперь в коде C # я использую такой цикл, как этот

TypeDictionary.Enumerator tdEnum = MyTypeDictionary.GetEnumerator();

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

   // More code here
}

для перебора элементов коллекции. Проблема в том, что в отдельных случаях мне нужно проверить, достиг ли определенный счетчик конца коллекции, в C ++ я бы сделал такую ​​проверку:

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

Но я просто не знаю, как справиться с этой ситуацией в C #, есть идеи?

Спасибо.
Томмазо

Ответы [ 5 ]

12 голосов
/ 26 апреля 2010

Вот довольно простой способ сделать это.

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

Я нашел онлайн-учебник, который также может помочь вам понять, как это работает.

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

4 голосов
/ 26 апреля 2010

У меня есть класс «умного итератора» в MiscUtil , который может оказаться полезным. Это позволяет вам проверить, смотрите ли вы в начале или конце последовательности, а также индекс в последовательности. См. страницу использования для получения дополнительной информации.

Конечно, в большинстве случаев вы можете просто сделать это вручную, используя результат MoveNext(), но иногда дополнительная инкапсуляция оказывается полезной.

Обратите внимание, что по необходимости этот итератор всегда будет использовать на одно значение больше, чем получено, чтобы узнать, достигнуто ли оно до конца. В большинстве случаев это не проблема, но при отладке это может иногда вызывать странные ощущения.

4 голосов
/ 26 апреля 2010

Вы знаете, что находитесь в конце итератора, когда MoveNext() возвращает false. В противном случае вам необходимо перейти на более описательную структуру данных, например IList<T>.

2 голосов
/ 12 сентября 2014

Использование шаблона декоратора для хранения значения, если перечислитель завершился, является верным подходом. Поскольку он реализует IEnumerator, вы не столкнетесь с трудностями при его замене в своем коде.

Вот тестовый класс:

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; }
        }
    }
}
1 голос
/ 26 апреля 2010

Исходя из C ++, вы можете быть не в курсе синтаксиса C #. Возможно, вы могли бы просто использовать конструкцию foreach, чтобы избежать всего теста вместе. Следующий код будет выполнен один раз для каждого элемента в вашем словаре:

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