简体   繁体   中英

How does IEnumerable<T>.Reverse work?

I am checking out the code in the reflector, but I haven't yet found out how it can enumerate through a collection backwards?

Since there is no count information, and enumeration always starts from the "start" of the collection, right?

Is it a drawback in the .NET framework? Is the cost higher than regular enumeration?

In short, it buffers everything and then walks through it backwards. Not efficient, but then, neither is OrderBy from that perspective.

In LINQ-to-Objects, there are buffering operations (Reverse, OrderBy, GroupBy, etc) and non-buffering operations (Where, Take, Skip, etc).


As an example of a non-buffering Reverse implementation using IList<T> , consider:

public static IEnumerable<T> Reverse<T>(this IList<T> list) {
    for (int i = list.Count - 1; i >= 0; i--) {
        yield return list[i];
    }
}

Note that this is still a little susceptible to bugs if you mutate the list while iterating it... so don't do that ;-p

It works by copying the underlying IEnumerable<T> to an array, then enumerating over that array backward. If the underlying IEnumerable<T> implements ICollection<T> (like T[], List<T>, etc.), then the copy step is skipped and the enumerator just iterates over the underlying collection directly.

For more information, check out System.Linq.Buffer<TElement> in Reflector.

Edit: The underlying collection is always copied, even if it's an ICollection<TElement>. This prevents changes in the underlying collection from being propagated by the Buffer<TElement>.

it loads all items to memory and then steps through them (backwards). this is far less efficient.

Edit: Opps, wrote wrong test for reverse, my apology for wrong answer. It does buffer after correcting test(using enumerable returned by Reverse())

Looks like Reverse extension method only works when collection is populated. While using yield return it does not do anything.

Ran into problem using reverse thought it must buffer for it to work, found it does not work with yield. It just go pass it and don't do anything. below is my test code.

        [TestMethod]
    public void loopTest()
    {
        var series = this.GetSeries();

        series.Reverse();

        foreach (var l in series)
        {
            Debug.WriteLine(l);
        }
    }

    private IEnumerable<long> GetSeries()
    {
        var series = new List<long>() { 1, 2, 3, 4 };

        foreach (var entry in series)
        {
            Debug.WriteLine(entry);

            yield return entry;
        }
    }

Reverse do not call GetSeries function at all, all buffer talks in this forum looks from thin air.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM