有没有办法使用yield块来实现 IEnumerator<T> 可以向后移动(MoveLast())以及转发?

有帮助吗?

解决方案

不直接从迭代器块,无

然而,主叫方可以总是缓冲的结果,例如成List<T>,或只是调用Reverse() - 但是这并不总是适用

其他提示

没有,由C#编译器生成的状态机是严格前进。

,它甚至没有意义的,倒退的情况较多。想象一下,一个迭代器从网络流读取 - 往回走,那就要记住,它曾经读到的一切,因为它无法倒带时间,并再次询问网络对于数据

在一些有损方式产生的数据(同上任何想象其退回康威的生命一个新的董事会在每次迭代的迭代器 - 有可能都曾有过的的以前的一个,所以多块电路板往回走,你再要记住你已经返回了什么已经。)

我知道这个线程是超级老,但它是必要指出

foreach(var item in someCollection)
{
    // Do something
}

...被编译为:

var enumerator = someCollection.GetEnumerator()
while (enumerator.MoveNext())
{
    var item = enumerator.Current;
    // Do something
}

所以,如果你不介意的“MoveNext的”语法,你可以很容易地实现IEnumerator,并添加一个“MovePrevious”。你就不能,如果你使用“的foreach”扭转方向,但如果使用while循环,你会能够逆转方向。

或者...如果你想“的foreach”反向列表(非双向),你可以把yield语句的优势。

public static IEnumerable<TItem> Get<TItem>(IList<TItem> list)
{
    if (list == null)
        yield break;

    for (int i = list.Count - 1; i > -1; i--)
        yield return list[i];
}

或者......如果你想要去的长期路线反向的foreach你可以实现自己的IEnumerable / IEnumerator的

public static class ReverseEnumerable
{
    public static IEnumerable<TItem> Get<TItem>(IList<TItem> list)
    {
        return new ReverseEnumerable<TItem>(list);
    }
}

public struct ReverseEnumerable<TItem> : IEnumerable<TItem>
{
    private readonly IList<TItem> _list;

    public ReverseEnumerable(IList<TItem> list)
    {
        this._list = list;
    }

    public IEnumerator<TItem> GetEnumerator()
    {
        if (this._list == null)
            return Enumerable.Empty<TItem>().GetEnumerator();

        return new ReverseEnumator<TItem>(this._list);
    }

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

public struct ReverseEnumator<TItem> : IEnumerator<TItem>
{
    private readonly IList<TItem> _list;
    private int _currentIndex;

    public ReverseEnumator(IList<TItem> list)
    {
        this._currentIndex = list.Count;
        this._list = list;
    }

    public bool MoveNext()
    {
        if (--this._currentIndex > -1)
            return true;

        return false;
    }

    public void Reset()
    {
        this._currentIndex = -1;
    }

    public void Dispose() { }

    public TItem Current
    {
        get
        {
            if (this._currentIndex < 0)
                return default(TItem);

            if (this._currentIndex >= this._list.Count)
                return default(TItem);

            return this._list[this._currentIndex];
        }
    }

    object IEnumerator.Current
    {
        get { return this.Current; }
    }
}

没有。其中的IEnumerator的局限性在于它保持其当前状态,并且它不记得以前的状态。其结果是,IEnumerable的是只进

如果您需要不放先前状态,通过这些对象读了IEnumerable成列表或链表和列举代替。

实际上,似乎有一种方法描述在 加速 C# 2008. 。不幸的是,两个页面在预览中不可见,并且它必须依赖于反射(其结果可以像往常一样被缓存),但您可以了解要点。

不。使用 yield 结果是 IEnumerable 这是单向的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top