IEnumerable <t> .Reverse是如何工作的?</t>

时间:2009-06-26 22:47:00

标签: c# .net linq collections

我正在检查反射器中的代码,但我还没有找到它如何通过向后枚举集合?

由于没有计数信息,枚举总是从集合的“开始”开始,对吧?

这是.NET框架中的缺点吗?成本是否高于常规枚举?

4 个答案:

答案 0 :(得分:41)

简而言之,它会缓冲一切,然后向后走。效率不高,但从那个角度来看,OrderBy也不是。

在LINQ-to-Objects中,有缓冲操作(Reverse,OrderBy,GroupBy等)和非缓冲操作(Where,Take,Skip等)。


作为使用Reverse的非缓冲IList<T>实施的示例,请考虑:

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

请注意,如果你在迭代它时改变列表,这仍然有点容易受到错误...所以不要这样做;-p

答案 1 :(得分:6)

它通过复制底层IEnumerable&lt; T&gt;来工作。到一个数组,然后向后枚举该数组。 如果底层IEnumerable&lt; T&gt;实现ICollection&lt; T&gt; (如T [],List&lt; T&gt;等),然后跳过复制步骤,枚举器直接迭代底层集合。

有关更多信息,请查看System.Linq.Buffer&lt; TElement&gt;在Reflector。

编辑:始终复制基础集合,即使它是ICollection&lt; TElement&gt;。这可以防止底层集合中的更改被缓冲区&lt; TElement&gt;传播。

答案 2 :(得分:3)

它将所有项目加载到内存中,然后逐步执行(向后)。效率低得多。

答案 3 :(得分:-3)

编辑:Opps,为反向写了错误的测试,我为错误答案道歉。它在校正测试后会缓冲(使用Reverse()返回的枚举

看起来反向扩展方法仅在填充集合时有效。在使用收益率回报时,它没有做任何事情。

使用反向思考进入问题它必须缓冲它才能工作,发现它不适用于yield。它只是通过它,不做任何事情。下面是我的测试代码。

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

反向根本不调用GetSeries函数,本论坛中的所有缓冲区会话都是空气稀薄。