Подтвердить что ты не робот

Использование LINQ для объекта, у которого есть только GetEnumerator()

Можно ли использовать LINQ в объекте, который предоставляет только объекты Add(), Remove(), Count(), Item() и GetEnumerator() из System.Collections.IEnumerator?

4b9b3361

Ответ 1

Существующие методы расширения Linq работают с объектами, которые реализуют IEnumerable<T>. Я предполагаю, что ваш объект реализует не общий интерфейс IEnumerable. В этом случае вы можете использовать метод расширения Cast<T>, чтобы получить общую обертку IEnumerable<T>. Например, если элементы имеют тип int:

var wrapper = myObject.Cast<int>();

Теперь вы можете использовать Linq на обертке

Ответ 2

Не напрямую. Вы могли бы довольно легко написать SingleShotEnumerable<T>, хотя:

 public sealed class SingleShotEnumerable<T> : IEnumerable<T>
 {
     private IEnumerator<T> enumerator;

     public SingleShotEnumerable(IEnumerator<T> enumerator)
     {
         if (enumerator == null)
         {
             throw new ArgumentNullException("enumerator");
         }
         this.enumerator = enumerator;
     }

     public IEnumerator<T> GetEnumerator()
     {
         if (enumerator == null)
         {
             throw new InvalidOperationException
                 ("GetEnumerator can only be called once");
         }
         var ret = enumerator;
         enumerator = null;
         return ret;
     }

     IEnumerator IEnumerable.GetEnumerator()
     {
         return GetEnumerator();
     }
 }

Предполагается, что у вас есть IEnumerator<T>. Если у вас есть только IEnumerator, вы можете написать что-то подобное, только реализуя IEnumerable, затем используйте Cast или OfType, чтобы перейти к IEnumerable<T>.

(Примечание: это не потокобезопасно. Вы можете сделать это с помощью блокировок, если хотите.)

Затем вы можете:

 var filtered = from person in new SingleShotEnumerable<Person>(personEnumerator)
                where person.Age > 18
                select person.Name;

... но вы не можете использовать запрос дважды.

Как вы попали в странную ситуацию, имея только IEnumerator<T>? Это довольно редко. Посмотрите, можете ли вы создать свой путь вокруг этого, чтобы избежать необходимости делать что-то вроде выше, что довольно хрупко.

(Альтернативой было бы "слить" IEnumerator<T> в List<T> или что-то подобное, но у этого есть проблемы, связанные с большими или потенциально бесконечными последовательностями.)

Ответ 3

Нет, вы не можете. Все методы LINQ - это методы расширения для интерфейса IEnumerable<T>.

Итак, вам нужно реализовать IEnumerable<T>, чтобы использовать LINQ с вашими собственными коллекциями.