В чем причина того, что интерфейсы IEnumerable / IEnumerable <T>имеют только MoveNext? - PullRequest
7 голосов
/ 27 ноября 2009

В основном мне интересно, почему MS решила внедрить перечислитель, который поддерживает только движение вперед: MoveNext().

Не более ли гибко применять MovePrevious для этого широко используемого интерфейса в .NET Framework?

Я могу себе представить, что это делает Linq.Reverse намного проще в реализации для MS и более эффективным по производительности, но я не уверен, что это замедляет другие вещи или накладывает огромные затраты на все остальное.

Кто-нибудь с большим знанием этого предмета может дать больше информации по этому вопросу, пожалуйста? то есть плюсы и минусы наличия или отсутствия наличия MovePrevious в IEnumerable/IEnumerable<T>.

Ответы [ 5 ]

21 голосов
/ 27 ноября 2009

IEnumerable[<T>] представляет последовательность данных, а не список произвольного доступа. Не все последовательности могут быть обращены или даже воспроизведены. Последовательности, основанные на сетевых потоках, доступе к базе данных и т. Д. - или эта красота:

IEnumerable<int> GetData() {
    Random rand = new Random();
    while(true) { yield return rand.Next(); }
}

Лучшее, что вы можете сделать, это начать заново - не , вызвав Reset() (что устарело), ​​но вместо этого получив свежий перечислитель.

Даже без Random несложно придумать простые последовательности, которые не могут быть обращены (без буферизации и обращения буфера). Для того, что вы хотите, рассмотрите вместо этого IList[<T>] - вы можете получить доступ к данным через индексатор в любом порядке.

6 голосов
/ 27 ноября 2009

Существует много типов данных, в которых нет смысла использовать MovePrevious. Например, если вы получаете данные из сетевого подключения, для предоставления MovePrevious потребуется буферизация всего потока на тот случай, если вы вызвали этот метод. Это потратило бы огромное количество памяти.

Сказав это, может быть полезно иметь другой тип , который поддерживает MoveNext и MovePrevious (например, двусвязный список может поддерживать это).

1 голос
/ 27 ноября 2009

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

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

Есть и другие интерфейсы, кроме IList, IQueryable. Использование наиболее подходящего для сценария, также сообщает тип использования, который он должен иметь.

1 голос
/ 27 ноября 2009

Реализация MovePrevious сделает его на 1001 * намного тяжелее интерфейс. В то время как для некоторых источников (массив, классы-контейнеры) MovePrevious будет тривиальным, для многих других источников это потребует дорогой буферизации или исключит эти источники. Сетевые потоки и соединения с базой данных не поддерживают операции поиска.

0 голосов
/ 27 ноября 2009

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

Также вы можете иметь функциональный код, используя итераторы, которые никогда не «заканчиваются» как таковые, например

yield value++;

Вы будете просто получать увеличивающиеся числа, пока не остановитесь.

...