Подтвердить что ты не робот

Как работает IEnumerable <T>.Reverse?

Я проверяю код в отражателе, но я еще не понял, как он может перечислить коллекцию назад?

Поскольку нет информации о счете, и перечисление всегда начинается с "начала" коллекции, правильно?

Является ли это недостатком в .NET Framework? Является ли стоимость выше обычной переписи?

4b9b3361

Ответ 1

Короче говоря, он буферизует все, а затем проходит через него назад. Неэффективно, но тогда и 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

Ответ 2

Он работает, копируя основной IEnumerable <T> к массиву, а затем перечислить этот массив назад. Если базовый IEnumerable <T> реализует ICollection <T> (например, T [], List <T> , и т.д.), то шаг копирования пропускается, и счетчик просто выполняет итерацию по базовой коллекции напрямую.

Для получения дополнительной информации см. System.Linq.Buffer <TElement> в рефлекторе.

Изменить: базовая коллекция всегда копируется, даже если она является ICollection <TElement> . Это предотвращает распространение изменений в базовой коллекции из буфера <TElement> .

Ответ 3

он загружает все элементы в память, а затем выполняет их шаги (назад). это гораздо менее эффективно.

Ответ 4

Изменить: Opps, написал неправильный тест для обратного, извинения за неправильный ответ. Он выполняет буферизацию после исправления теста (с использованием перечислимого значения, возвращаемого функцией Reverse())

Похоже, метод обратного расширения работает только при заполнении коллекции. При использовании доходности возврата он ничего не делает.

Перейдя к проблеме, используя обратную связь, она должна буферизировать ее работу, обнаружив, что она не работает с выходом. Он просто проходит мимо и ничего не делает. ниже мой тестовый код.

        [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 вообще, все разговоры с буферами в этом форуме выглядят из-за тонкого воздуха.