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

Почему существует две совершенно разные версии Reverse для List и IEnumerable?

Для объекта List у нас есть метод Reverse().
Он отменяет порядок списка "на месте", он ничего не возвращает.

Для объекта IEnumerable у нас есть метод расширения, называемый Reverse().
Он возвращает другой IEnumerable.

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

Поэтому я могу либо сделать это:

for(int i = list.Count - 1; i >=0; i--)

или

foreach(var item in list.AsEnumerable().Reverse())

Я нашел его менее читаемым, чем если бы у меня был IEnumerable, просто сделайте

foreach(var item in list.Reverse())

Я не могу понять, почему эти 2 метода были реализованы таким образом, с тем же именем. Это довольно раздражает и запутывает.

Почему нет расширения под названием BackwardsIterator() вместо Reverse() для всех IEnumerable?

Меня очень интересует историческая причина этого выбора, больше, чем "как это сделать"!

4b9b3361

Ответ 1

Стоит отметить, что метод списка намного старше метода расширения. Именование, вероятно, сохранилось так же, как Reverse кажется более кратким, чем BackwardsIterator.

Если вы хотите обойти версию списка и перейти к методу расширения, вам нужно обработать список как IEnumerable<T>:

var numbers = new List<int>();
numbers.Reverse(); // hits list
(numbers as IEnumerable<int>).Reverse(); // hits extension

Или вызовите метод расширения как статический метод:

Enumerable.Reverse(numbers);

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

Ответ 2

Создайте свой собственный BackwardsIterator!

public static IEnumerable BackwardsIterator(this List lst)
{
    for(int i = lst.Count - 1; i >=0; i--)
    {
        yield return lst[i];
    }
}

Ответ 3

Разница связана с тем, что List является классом, а IEnumerable - интерфейсом. Это означает, что объект List имеет одну реализацию (ну, это реализация), и эффект Reverse гарантированно сохраняется во внутреннем состоянии объекта.

С IEnumerable он отличается: любой объект может его реализовать, без обязательства реализовать метод Reverse, потому что он не является частью интерфейса. Метод расширения Reverse() может только перечислять перечислитель IEnumerable в обратном порядке, но никогда не изменять внутреннее состояние объекта.

Но List.Reverse уже существовало, когда Enumerable и его методы расширения были введены. Если бы они были изобретены в то же время, List.Reverse также мог бы быть апатридом для равномерного распределения. Кто знает.