C# foreach字典<>;。值或foreach字典<&燃气轮机;

C# foreach字典<>;。值或foreach字典<&燃气轮机;,c#,foreach,iteration,containers,C#,Foreach,Iteration,Containers,我想知道C#中这两种迭代Dictionary集合的详细信息: 风格二: foreach (var it in xydic) { Y y = it.Value; use y... } 我多年来一直是C++开发人员(现在我在一个C项目中工作),我不知道“代码>字典集合如何工作,内存布局或元素是如何被迭代的,所以我想知道: xydic.Values创建一个临时的列表?我没有看到任何关于创建临时列表的信息 如果创建了一个临时列表,这是否意味着集合将迭代两次:第一次创建列表,第二次迭代列表本身 如果以上

我想知道C#中这两种迭代
Dictionary
集合的详细信息:

风格二:

foreach (var it in xydic) { Y y = it.Value; use y... }

我多年来一直是C++开发人员(现在我在一个C项目中工作),我不知道“代码>字典<代码>集合如何工作,内存布局或元素是如何被迭代的,所以我想知道:

xydic.Values
创建一个临时的
列表
?我没有看到任何关于创建临时列表的信息

如果创建了一个临时列表,这是否意味着集合将迭代两次:第一次创建
列表,第二次迭代列表本身

如果以上问题的答案是肯定的,那么第二种风格应该更有效,使得第一种风格几乎毫无用处,所以我认为我在某些方面应该是错的


我觉得这个问题应该在某个地方得到回答,但我找不到答案。

检索
字典的
属性是一个O(1)操作()。嵌套类型
Dictionary.ValueCollection
是字典的简单包装器,因此创建字典时不需要迭代

调用
GetEnumerator()
时,您将获得嵌套的
Dictionary.ValueCollection.Enumerator
结构的实例。它直接通过
字典
私有
数组
条目
访问条目

你可以看到这张照片

因此,您上面的“风格一”是一种良好且清晰的做事方式,没有性能开销

请注意,获取值的顺序是任意的。一旦
字典
在开始
foreach
之前进行了多次插入和删除,您就不知道底层数组
条目
是如何组织的


然而,“风格一”和“风格二”的顺序是一样的;两者都以相同的方式访问
字典的私有
条目
数组。

没有创建一个
列表
,不。它甚至没有将整个值集拉入一个单独的数据结构。它所做的只是创建一个枚举器,可以对这些值进行迭代。它所做的事情与直接迭代字典时发生的完全相同;不同之处在于,不是为每对对象构造一个
KeyValuePair
对象,而是只提供该对的一半。除此之外,迭代过程是相同的。

所有3种方法(
和字典的迭代)的行为都是相同的-迭代字典中项目的内部集合。没有创建额外的列表/数组

唯一的“额外”工作是检查字典是否在迭代开始后被修改(整数比较)


在这两种情况下,您都可以在

中查看确切的详细信息,而不是临时收集。迭代器使用内部状态机来记住当前项是什么,并使用MoveNext方法来获取nex项

如果您查看IL代码,您将看到foreach内部发生的更多细节。这是我的电话号码

void Main()
{
    var dictionary = new Dictionary<int, string> { { 1, "one" }, { 2, "two" }};

    foreach (var item in dictionary.Values)
    {
        Console.WriteLine(item);
    }
}
void Main()
{
var dictionary=新字典{{1,“一”},{2,“二”};
foreach(dictionary.Values中的变量项)
{
控制台写入线(项目);
}
}
IL代码:

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         
IL_0000:nop
IL_0001:newobj系统.集合.通用.词典..ctor
IL_0006:stloc.1
IL_0007:ldloc.1
IL_0008:ldc.i4.1
IL_0009:ldstr“一”
IL_000E:callvirt System.Collections.Generic.Dictionary.Add
IL_0013:没有
IL_0014:ldloc.1
IL_0015:ldc.i4.2
IL_0016:ldstr“两个”
IL_001B:callvirt System.Collections.Generic.Dictionary.Add
伊卢0020:没有
IL_0021:ldloc.1
IL_0022:stloc.0//字典
伊卢0023:没有
IL_0024:ldloc.0//字典
IL_0025:callvirt System.Collections.Generic.Dictionary.get_值
IL_002A:callvirt System.Collections.Generic.Dictionary+ValueCollection.GetEnumerator
IL_002F:stloc.2
IL_0030:br.s IL_0043
IL_0032:ldloca.s 02
IL_0034:调用System.Collections.Generic.Dictionary+ValueCollection+Enumerator.get_Current
IL_0039:stloc.3//项目
IL_003A:没有
ILU 003B:ldloc.3//项目
IL_003C:调用System.Console.WriteLine
IL_0041:没有
IL_0042:没有
IL_0043:ldloca.s 02
IL_0045:调用System.Collections.Generic.Dictionary+ValueCollection+Enumerator.MoveNext
IL_004A:brtrue.s IL_0032
IL_004C:离开。s IL_005D
ILU 004E:ldloca.s 02
IL_0050:受约束。System.Collections.Generic.Dictionary+ValueCollection.Enumerator
IL_0056:callvirt System.IDisposable.Dispose
IL_005B:没有
IL_005C:最后结束
IL_005D:ret

在C语言中,你不必担心内存问题。垃圾收集器将为您完成这项工作。如果你真的想看看
字典
类如何执行
.Values
或其他函数,你可以用
IlSpy
应用程序打开它,只需查看代码,你就可以查看它的具体实现方式。@Jasper我关心的更多是
是否创建了一个临时列表(意味着集合被迭代了两次)。当我提到我不知道内存布局时,我是说如果我知道,我可以自己推断答案:)@PaperBirdMaster为什么不简单地检查source-?创建一个临时列表(意味着集合被迭代了两次)C)你有垃圾收集器-不要考虑内存分配很多-让GC做它工作抱歉为一个愚蠢的和天真的问题,为一个可怜的C++开发者谁登陆C++世界最近…什么是ILDIL是中间语言。是我
void Main()
{
    var dictionary = new Dictionary<int, string> { { 1, "one" }, { 2, "two" }};

    foreach (var item in dictionary.Values)
    {
        Console.WriteLine(item);
    }
}
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