Гарантируется ли оператор .NET foreach повторение коллекции в том же порядке, в котором она была построена?

Коллега использовал цикл for для итерации List в каком-то написанном им коде C# и оставил комментарий: «Не использовал For Each, потому что не был уверен, что он выполняет итерацию по порядку. Кто знает, что сделает Microsoft». Например, предположим, что у нас есть список, построенный следующим образом:

var someList = new List<string>();

someList.Add("one");
someList.Add("two");
someList.Add("three");

мой коллега использовал что-то вроде этого:

for (int i = 0; i < someList.Count; i++)    
{
    System.Diagnostics.Debug.WriteLine(someList[i]);
}

вместо этого:

foreach (var item in someList)              
{
    System.Diagnostics.Debug.WriteLine(item);
}

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


person raven    schedule 04.03.2009    source источник


Ответы (3)


Ваш вопрос касается List<T>, который поддерживает порядок.

foreach сам по себе ничего не гарантирует. Он просто запрашивает объект, предоставленный его перечислителю, который потенциально может делать что угодно.

person Rex M    schedule 04.03.2009
comment
Проверяю, смогу ли я преодолеть эффект Скита. Скрещенные пальцы. - person Rex M; 05.03.2009
comment
В настоящее время у вас на один больше, чем у меня из-за моего собственного голоса. Я предполагаю, что это не эффект Скита, который вы имели в виду;) - person Jon Skeet; 05.03.2009
comment
Спасибо. Я недостаточно углубился в документацию: msdn. microsoft.com/en-us/library/aa288257(VS.71).aspx - person raven; 05.03.2009

Это зависит от коллекции:

  • Для List<T> это гарантированный порядок размещения. (Это предполагает только вызовы Add, как показано на рисунке. Если вы вставите элементы в список в определенных местах, они будут возвращены в правильных точках, как вы и ожидали.) В основном это тот же порядок, который вы получили бы, взяв list[0], list[1] , list[2] и т. д.
  • Для Dictionary<TKey, TValue> нет гарантированного порядка.
  • Для SortedList<TKey, TValue> (и подобных) это будет в порядке сравнения ключей - в этом суть типа.
  • Массивы всегда выходят в порядке элементов.
person Jon Skeet    schedule 04.03.2009
comment
Хотя вы правы, я бы по-прежнему утверждал, что foreach ТОЛЬКО для перебора всех объектов в коллекции и никоим образом не гарантирует какой-либо порядок. Порядок, который будет выбирать foreach, зависит от реализации коллекции. Таким образом, использование foreach не имеет гарантированного поведения. - person DevinB; 05.03.2009
comment
@devinb Я думаю, что именно это говорит @Jon. - person Rex M; 05.03.2009
comment
Ну, foreach гарантированно использует GetEnumerator из коллекции, поэтому, если вы знаете порядок итератора коллекции, вам гарантирован такой же порядок из foreach. Например, вполне разумно полагаться на то, что он выполняет итерацию по списку по порядку. - person Jon Skeet; 05.03.2009
comment
@ Рекс, я полагаю, я не ясно выразился. Я пытался сказать, что порядок foreach следует рассматривать как побочный эффект. В то время как цикл for имеет гарантированный порядок. Джон умолчал об этом факте и намекнул, что следует использовать foreach. Я чувствую, что если индексированный порядок важен, то цикл for безопаснее. - person DevinB; 05.03.2009
comment
@both: Ха... ну, теперь я просто выгляжу глупо. Я оставлю свои комментарии здесь для потомков, чтобы не было похоже, что вы, ребята, ничего не ответили. - person DevinB; 05.03.2009

Чтобы конкретно ответить на вопрос, "foreach" возвращает порядок, который возвращает функция .GetEnumerator(). Для списков это порядок добавления элементов в конец. Для словарей это, вероятно, порядок корзин, в которых были назначены вещи.

person Jeff Moser    schedule 04.03.2009