heltonbiker
heltonbiker

Reputation: 27575

How to make my InfiniteLoopingList class implement IEnumerable?

I am making a prototype application and for that I designed a class that behaves like an infinite looping list. That is, if my internal list contains 100 values, when I ask for the 101st value, I get the first, the 102nd yields the second, and so on, repeating.

So I would like to write the following code:

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

And for that I need to implement IEnumerable suitable, as I understand.

Here is my current code:

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 ?? :(
    }
}

Upvotes: 2

Views: 82

Answers (3)

Dmitry
Dmitry

Reputation: 14059

Since you implemented the indexer property, you could do it via the simplest way as follows:

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

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

EDIT
Please notice, that this is not really infinite loop. This approach will only work until i = int.MaxValue. Thanks to @oleksii.

Upvotes: 3

Mehrzad Chehraz
Mehrzad Chehraz

Reputation: 5137

You can implement the IEnumerator interface:

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;
    }
}

and then return an instance of it in the GetEnumerator methods:

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

public IEnumerator<T> IEnumerable<T>.GetEnumerator() {
    return new InifniteEnumerator(this, 100);
}

Upvotes: 0

spender
spender

Reputation: 120440

You don't need a class for this...

An extension method will do the trick:

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;
            }
        }
    }
}

Now you can take a sequence and make it a looping, infinite sequence:

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

Upvotes: 2

Related Questions