foreach Dictionary<>.Values or foreach Dictionary<>

后端 未结 4 1475
忘掉有多难
忘掉有多难 2021-01-07 06:54

I want to know the details of this two styles of iterating Dictionary collections in C#:

Dictionary xydic = new Dictionary

        
相关标签:
4条回答
  • 2021-01-07 07:26

    Retrieving the .Values property of a Dictionary<,> is an O(1) operation (documented). The nested type Dictionary<,>.ValueCollection is a simple wrapper around the dictionary, so there is no iterating in creating it.

    On calling GetEnumerator(), you get an instance of the nested, nested Dictionary<,>.ValueCollection.Enumerator struct. It acccesses the entries directly through the private array entries of the Dictionary<,>.

    You can see the source code.

    So your "Style one" above is a good and clear way of doing things, with no performance overhead.

    Note that the order in which you get the values, is arbitrary. You do not know how the underlying array entries is organized, once the Dictionary<,> has had many insertions and removals before you start foreaching it.

    However, the order you get with "Style one" and "Style two" is the same; both access the private entries array of the Dictionary<,> in the same way.

    0 讨论(0)
  • 2021-01-07 07:28

    In both cases you are getting iterator and not temporary collection. Iterator is using internal state machine to remember what is the current item, and it uses MoveNext method to get nex item.

    If you look at IL code you will see more details what is going on inside of foreach. Here is the IL for

    void Main()
    {
        var dictionary = new Dictionary<int, string> { { 1, "one" }, { 2, "two" }};
    
        foreach (var item in dictionary.Values)
        {
            Console.WriteLine(item);
        }
    }
    

    IL Code:

    IL_0000:  nop         
    IL_0001:  newobj      System.Collections.Generic.Dictionary<System.Int32,System.String>..ctor
    IL_0006:  stloc.1     
    IL_0007:  ldloc.1     
    IL_0008:  ldc.i4.1    
    IL_0009:  ldstr       "one"
    IL_000E:  callvirt    System.Collections.Generic.Dictionary<System.Int32,System.String>.Add
    IL_0013:  nop         
    IL_0014:  ldloc.1     
    IL_0015:  ldc.i4.2    
    IL_0016:  ldstr       "two"
    IL_001B:  callvirt    System.Collections.Generic.Dictionary<System.Int32,System.String>.Add
    IL_0020:  nop         
    IL_0021:  ldloc.1     
    IL_0022:  stloc.0     // dictionary
    IL_0023:  nop         
    IL_0024:  ldloc.0     // dictionary
    IL_0025:  callvirt    System.Collections.Generic.Dictionary<System.Int32,System.String>.get_Values
    IL_002A:  callvirt    System.Collections.Generic.Dictionary<System.Int32,System.String>+ValueCollection.GetEnumerator
    IL_002F:  stloc.2     
    IL_0030:  br.s        IL_0043
    IL_0032:  ldloca.s    02 
    IL_0034:  call        System.Collections.Generic.Dictionary<System.Int32,System.String>+ValueCollection+Enumerator.get_Current
    IL_0039:  stloc.3     // item
    IL_003A:  nop         
    IL_003B:  ldloc.3     // item
    IL_003C:  call        System.Console.WriteLine
    IL_0041:  nop         
    IL_0042:  nop         
    IL_0043:  ldloca.s    02 
    IL_0045:  call        System.Collections.Generic.Dictionary<System.Int32,System.String>+ValueCollection+Enumerator.MoveNext
    IL_004A:  brtrue.s    IL_0032
    IL_004C:  leave.s     IL_005D
    IL_004E:  ldloca.s    02 
    IL_0050:  constrained. System.Collections.Generic.Dictionary<,>+ValueCollection.Enumerator
    IL_0056:  callvirt    System.IDisposable.Dispose
    IL_005B:  nop         
    IL_005C:  endfinally  
    IL_005D:  ret         
    
    0 讨论(0)
  • 2021-01-07 07:41

    Values is not creating a List<T>, no. It's not even pulling the entire set of values into a separate data structure. All it's doing is creating an enumerator that can iterate over the values. It's doing exactly the same thing that happens when you iterate the dictionary directly; the difference is that instead of constructing a KeyValuePair object for each pair of objects, its only giving you one half of the pair. Other than that, the iteration process is the same.

    0 讨论(0)
  • 2021-01-07 07:41

    All 3 methods (Keys, Values and just iteration of dictionary) behave the same - iterate internal collection of items in the dictionary. There is no extra lists/arrays created.

    The only "extra" work is to check if dictionary was modified after iteration is started (integer comparison).

    You can check exact details in the reference source

    0 讨论(0)
提交回复
热议问题