Как узнать, достиг ли перечислитель конца коллекции в С#?

Я переношу библиотеку с С++ на С#. В старой библиотеке используются векторы из С++, а в С# я использую универсальные словари, потому что они на самом деле являются хорошей структурой данных для того, что я делаю (у каждого элемента есть идентификатор, затем я просто использую 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

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

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


person tunnuz    schedule 26.04.2010    source источник


Ответы (5)


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

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

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

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

person Robert Greiner    schedule 26.04.2010

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

person Robert Davis    schedule 26.04.2010

У меня есть класс "умный итератор" в MiscUtil, который может оказаться полезным. Это позволяет вам проверить, смотрите ли вы в настоящее время на начало или конец последовательности, а также на индекс в последовательности. Дополнительную информацию см. на странице использования.

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

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

person Jon Skeet    schedule 26.04.2010
comment
Спасибо за вашу библиотеку, я добавил ее в закладки, но на этот раз я просто выберу быстрое решение. :) - person tunnuz; 26.04.2010

Использование шаблона декоратора для хранения значения, если перечислитель закончился, является допустимым подходом. Поскольку он реализует 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; }
        }
    }
}
person Fabio    schedule 12.09.2014
comment
Перечислениеdили? опечатка? Должен быть Enumeratили - person IlPADlI; 09.02.2015
comment
Да, учитывая, что пример был написан на английском языке, это опечатка (хотя на моем родном языке это слово означает перечислитель). Однако это имя класса, поэтому оно не влияет на результат. - person Fabio; 10.02.2015

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

foreach (var element in MyTypeDictionary)
{
    // More code here
}
person MEMark    schedule 26.04.2010