如何使我的 InfiniteLoopingList class 实现 IEnumerable?

How to make my InfiniteLoopingList class implement IEnumerable?

我正在制作原型应用程序,为此我设计了一个 class,它的行为类似于无限循环列表。也就是说,如果我的内部列表包含 100 个值,当我请求第 101 个值时,我得到第一个,第 102 个得到第二个,依此类推,重复。

所以我想写下面的代码:

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

你不需要 class 这个...

扩展方法可以解决问题:

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

您可以实现 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;
    }
}

然后 return 它在 GetEnumerator 方法中的一个实例:

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

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

由于您实施了索引器 属性,您可以通过以下最简单的方式完成:

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

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

编辑
请注意,这并不是真正的无限循环。此方法仅在 i = int.MaxValue 之前有效。感谢@oleksii。