Каков наилучший способ конвертировать IEnumerator в универсальный IEnumerator? - PullRequest
30 голосов
/ 06 мая 2009

Я пишу настраиваемую коллекцию ConfigurationElementCollection для настраиваемого ConfigurationHandler в C # .NET 3.5 и хочу представить IEnumerator в качестве универсального IEnumerator.

Каков наилучший способ добиться этого?

Я сейчас использую код:

public new IEnumerator<GenericObject> GetEnumerator()
{
  var list = new List();
  var baseEnum = base.GetEnumerator();
  while(baseEnum.MoveNext())
  {
    var obj = baseEnum.Current as GenericObject;
    if (obj != null)
      list.Add(obj);
  }
  return list.GetEnumerator();
}

Приветствия

Ответы [ 5 ]

50 голосов
/ 06 мая 2009

Я не верю, что в фреймворке что-то есть, но вы легко могли бы написать:

IEnumerator<T> Cast<T>(IEnumerator iterator)
{
    while (iterator.MoveNext())
    {
        yield return (T) iterator.Current;
    }
}

Соблазнительно просто вызвать Enumerable.Cast<T> из LINQ, а затем вызвать GetEnumerator() для результата - но если ваш класс уже реализует IEnumerable<T> и T является типом значения, который действует как неоперативный, поэтому GetEnumerator() вызов рекурсивно и выдает StackOverflowException. Безопасно использовать return foo.Cast<T>.GetEnumerator();, когда foo определенно является другим объектом (который не делегируется обратно этому объекту), но в противном случае вам, вероятно, лучше использовать приведенный выше код.

3 голосов
/ 06 мая 2009

IEnumerable<T> уже получено из IEnumerable, поэтому нет необходимости делать какие-либо преобразования. Вы можете просто привести к нему ... ну, на самом деле это неявный, не требуется приведение.

IEnumerable<T> enumerable = GetGenericFromSomewhere();
IEnumerable sadOldEnumerable = enumerable;
return sadOldEnumerable.GetEnumerator();

Обратный путь с LINQ не намного сложнее:

var fancyEnumerable = list.OfType<GenericObject>();
return fancyEnumerable.GetEnumerator();
1 голос
/ 11 июня 2015

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

Это код, который выбрасывал переполнение стека. Использование оператора foreach вызывает ту же функцию GetEnumerator, которую я пытаюсь перегрузить:

public new IEnumerator<T> GetEnumerator()
{
    foreach (T type in this)
    {
        yield return type;
    }
}

Я закончил с упрощенной версией исходного сообщения, так как вам не нужно использовать держатель списка.

public class ElementCollection<T> : ConfigurationElementCollection, IList<T>
    ...
    public new IEnumerator<T> GetEnumerator()
    {
        var baseEnum = base.GetEnumerator();
        while (baseEnum.MoveNext())
        {
            yield return baseEnum.Current as T;
        }
    }
    ...
}
0 голосов
/ 16 декабря 2014

Это работает для меня.

IEnumerator<DataColumn> columnEnumerator = dt.Columns.Cast<DataColumn>().GetEnumerator();
0 голосов
/ 06 мая 2009

Вы можете использовать OfType<T> и Cast<T>.

public static IEnumerable Digits()
{
    return new[]{1, 15, 68, 1235, 12390, 1239};
}

var enumerable = Digits().OfType<int>();
foreach (var item in enumerable)
    // var is here an int. Without the OfType<int(), it would be an object
    Console.WriteLine(i);

Чтобы получить IEnumerator<T> вместо IEnumerable<T>, вы можете просто позвонить на GetEnumerator()

var enumerator = Digits().OfType<int>().GetEnumerator();
...