С# foreach loop - это порядок * стабильность * гарантирован?
Предположим, что у меня есть данный набор. Не меняя коллекцию каким-либо образом, я дважды повторяю ее содержимое с помощью foreach. Запрещая космические лучи, а что нет, абсолютно ли гарантировано, что порядок будет согласован в обеих петлях?
В качестве альтернативы, учитывая HashSet<string>
с несколькими элементами, что может привести к неравномерности вывода из комментариев строк ниже:
{
var mySet = new HashSet<string>();
// Some code which populates the HashSet<string>
// Output1
printContents(mySet);
// Output2
printContents(mySet);
}
public void printContents(HashSet<string> set) {
foreach(var element in set) {
Console.WriteLine(element);
}
}
Было бы полезно, если бы я мог получить общий ответ, объясняющий, что приводит к тому, что реализация не отвечает критериям, описанным выше. В частности, меня интересуют Dictionary
, List
и массивы.
Ответы
Ответ 1
Перечисление массива гарантирует порядок.
Ожидается, что List
и List<T>
будут обеспечивать стабильный порядок (поскольку ожидается, что они будут реализовывать последовательно индексированные элементы).
Словарь, HashSet явно не гарантирует порядок. Очень маловероятно, что 2 обращения к итерации элементов один за другим возвратят элементы в другом порядке, но нет никаких гарантий или ожиданий. Нельзя ожидать какого-либо конкретного порядка.
Отсортированные версии словаря /HashSet возвращают элементы в порядке сортировки.
Другие объекты IEnumerable могут делать все, что захотят. Обычно один реализует итераторы таким образом, чтобы соответствовать ожиданиям пользователей. То есть перечисление чего-либо, имеющего неявный порядок, должно быть стабильным, если предусматривается явный порядок - ожидается, что он будет стабильным. Ожидается, что запрос к базе данных, который не указывает порядок, должен возвращать элементы в полуслучайном порядке.
Проверить этот вопрос для ссылок: Предоставляет ли цикл foreach в С# порядок оценки?
Ответ 2
Все, что реализует IEnumerable<T>
, делает это по-своему. Нет никакой общей гарантии, что любой сбор должен обеспечить стабильность.
Если вы конкретно ссылаетесь на Collection<T>
(http://msdn.microsoft.com/en-us/library/ms132397.aspx), я не вижу никакой конкретной гарантии в своей ссылке MSDN, что заказ согласован.
Возможно, он будет последовательным? Да. Есть ли письменная гарантия? Не то, что я могу найти.
Ответ 3
Для многих коллекций С# существуют отсортированные версии коллекции. Например, HashSet
относится к SortedSet
как Dictionary
относится к SortedDictionary
, Если вы работаете с чем-то, где порядок не важен, например, Dictionary
, вы не можете предположить, что порядок цикла будет вести себя одинаково каждый раз.
Ответ 4
В соответствии с вашим примером с HashSet<T>
теперь у нас есть исходный код для проверки: HashSet: Enumerator
Как бы то ни было, массив Slot[] set.m_slots
повторяется.
Объект массива изменяется только в методах TrimExcess
, Initialize
(оба из которых вызываются только в конструкторе), OnDeserialization
и SetCapacity
(вызываются только AddIfNotPresent
и AddOrGetLocation
).
Значения m_slots
изменяются только в методах, которые меняют элементы HashSet
(Clear
, Remove
, AddIfNotPresent
, IntersectWith
, SymmetricExceptWith
).
Итак, да, если ничто не касается набора, оно перечисляется в том же порядке.
Словарь: Перечислитель работает совершенно таким же образом, итерация Entry[] entries
, которая изменяется только при вызове таких нечитанных методов.