2015-04-23 3 views
2

Я делаю прототип приложения, и для этого я разработал класс, который ведет себя как бесконечный список циклов. То есть, если мой внутренний список содержит 100 значений, когда я запрашиваю 101-е значение, я получаю первый, 102-й дает второй и т. Д., Повторяя.Как заставить класс InfiniteLoopingList реализовать IEnumerable?

Так что я хотел бы написать следующий код:

var slice = loopingListInstance.Skip(123).Take(5); 

И для этого мне нужно реализовать IEnumerable подходящий, как я понимаю.

Вот мой текущий код:

public class InfiniteLoopingList : IEnumerable<double> 
{ 
    double[] _values = File.ReadLines(@"c:\file.txt") 
          .Select(s => double.Parse(s, CultureInfo.InvariantCulture)) 
          .ToArray(); 
    int _size; 

    public InfiniteLoopingList() 
    { 
     _size = _values.Length; 
    } 

    public double this[int i] 
    { 
     get { return _values[i % _size]; } 
     set { _values[i % _size] = value; } 
    } 

    public IEnumerator<double> GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     // ???? now what ?? :(
    } 
} 

ответ

3

Поскольку вы реализовали свойство индексатор, вы можете сделать это с помощью простой способ следующим образом:

public IEnumerator<double> GetEnumerator() 
{ 
    int i = 0; 
    while (true) 
     yield return this[i++]; 
} 

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

EDIT
Обратите внимание, что это не бесконечный цикл. Этот подход будет работать только до i = int.MaxValue. Благодаря @oleksii.

+0

Это похоже на то, что мне нужно. Собираюсь проверить его после обеда и вернуться, чтобы опубликовать некоторые отзывы. Благодаря! – heltonbiker

+0

@oleksii Yup, вы правы, это не совсем бесконечный цикл. Но я сомневаюсь, что кому-то действительно нужна бесконечная последовательность. Я обновил ответ, спасибо. – Dmitry

2

Вам не нужен класс для этого ...

метод расширения будет делать трюк:

public static class InfEx 
{ 
    public static IEnumerable<T> LoopForever<T>(this IEnumerable<T> src) 
    { 
     var data = new List<T>(); 
     foreach(var item in src) 
     { 
      data.Add(item); 
      yield return item; 
     } 

     for(;;) 
     { 
      foreach(var item in data) 
      { 
       yield return item; 
      } 
     } 
    } 
} 

Теперь вы может принимать последовательность и сделать ее циклической, бесконечной последовательностью:

IEnumerable<Foo> mySeq = ...; 
IEnumerable<Foo> infMySeq = mySeq.LoopForver(); 
IEnumerable<Foo> aSelectionOfInfMySeq = infMySeq.Skip(101).Take(5); 
+0

Так как это поможет мне в использовании этого: 'var slice = loopingListInstance.Skip (123) .Take (5);'? – heltonbiker

+1

Вместо 'ToList' вы можете сделать' src.GetEnumerator' и выполнить 'Reset' после каждого цикла. – Alex

+0

@Alex No. .ToList был явно выбран, потому что IEnumerable не гарантирует никаких повторных перечислений источника. – spender

0

Вы можете реализовать интерфейс IEnumerator:

class InifniteEnumerator<T> : IEnumerator<T> {   
    private int index = -1; 
    private IList<T> innerList; 
    private int repeatPos; 
    public InifniteEnumerator(IList<T> innerList, int repeatPos) { 
     this.innerList = innerList; 
     this.repeatPos = repeatPos; 
    } 
    public T Current { 
     get { 
      if (index == -1) { 
       throw new InvalidOperationException(); 
      } 
      return this.innerList[index]; 
     } 
    } 
    object IEnumerator.Current { 
     get { 
      return this.Current; 
     } 
    } 
    public void Dispose() { 

    } 
    public bool MoveNext() { 
     this.index++; 
     if (this.index == repeatPos) { 
      this.index = 0; 
     } 
     return true; 
    } 
    public void Reset() { 
     this.index = -1; 
    } 
} 

, а затем вернуть его экземпляр в методах GetEnumerator:

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

public IEnumerator<T> IEnumerable<T>.GetEnumerator() { 
    return new InifniteEnumerator(this, 100); 
} 
Смежные вопросы