简体   繁体   中英

C# foreach loop - is order *stability* guaranteed?

Suppose I have a given collection. Without ever changing the collection in any way, I loop through its contents twice with a foreach. Barring cosmic rays and what not, is it absolutely guaranteed that the order will be consistent in both loops?

Alternatively, given a HashSet<string> with a number of elements, what can cause the output from the the commented lines in the following to be unequal:

{
    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);
    }
}

It would be helpful if I could get a general answer explaining what causes an implementation to not meet the criteria described above. Specifically, though, I am interested in Dictionary , List and arrays.

Array enumeration guarantees order.

List and List<T> are expected to provide stable order (since they are expected to implement sequentially-indexed elements).

Dictionary, HashSet are explicitly do not guarantee order. Its is very unlikely that 2 calls to iterate items one after each other will return items in different order, but there is no guarantees or expectations. One should not expect any particular order.

Sorted versions of Dictionary/HashSet return items in sort order.

Other IEnumerable objects are free to do whatever they want. Normally one implements iterators in such a way that it matches user's expectations. Ie enumeration of something that have implicit order should be stable, if explicit order provided - expected to be stable. Query to database that does not specify order should be expected to return items in semi-random order.

Check this question for links: Does the foreach loop in C# guarantee an order of evaluation?

Everything that implements IEnumerable<T> does so in its own way. There is no general guarantee that any given collection must ensure stability.

If you are referring specifically to Collection<T> ( http://msdn.microsoft.com/en-us/library/ms132397.aspx ) I don't see any specific guarantee in its MSDN reference that ordering is consistent.

Will it probably be consistent? Yes. Is there a written guarantee? Not that I can find.

For many of the C# collections there are sorted versions of the collection. For instance, a HashSet is to a SortedSet as a Dictionary is to a SortedDictionary . If you're working with something where the order isn't important like the Dictionary then you can't assume the loop order will behave the same way every time.

As per your example with HashSet<T> , we now have source code to check: HashSet:Enumerator

As it is, the Slot[] set.m_slots array is iterated. The array object is only changed in the methods TrimExcess , Initialize (both of which are only called in the constructor), OnDeserialization , and SetCapacity (only called by AddIfNotPresent and AddOrGetLocation ).

The values of m_slots are only changed in methods that change elements of the HashSet ( Clear , Remove , AddIfNotPresent , IntersectWith , SymmetricExceptWith ).

So yes, if nothing touches the set, it enumerates in the same order.

Dictionary:Enumerator works in quite the same way, iterating an Entry[] entries that only changes when such non-readonly methods are called.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM