字典初始化如何在C#中工作?

时间:2014-01-24 12:52:53

标签: c# dictionary constructor

var maxDictionary = new Dictionary<int, double> { { 10, 40000 } };

在上面的代码中,编译器是否使用构造函数?或者编译器是否创建了KeyValuePair并添加到字典中?我试图理解编译器如何解释它。

3 个答案:

答案 0 :(得分:19)

是的,编译器使用默认的无参数构造函数,然后通过Dictionary.Add方法添加集合初始化程序中指定的所有值。正如Jon指出的那样,你的代码被编译成

Dictionary<int, double> maxDictionary2;
Dictionary<int, double> maxDictionary;

maxDictionary2 = new Dictionary<int, double>();
maxDictionary2.Add(10, 40000.0);
maxDictionary = maxDictionary2;

生成IL:

.maxstack 3
.locals init (
     [0] class [mscorlib]Dictionary`2<int32, float64> maxDictionary,
     [1] class [mscorlib]Dictionary`2<int32, float64> maxDictionary2)
L_0000: nop 
L_0001: newobj instance void [mscorlib]Dictionary`2<int32, float64>::.ctor()
L_0006: stloc.1 
L_0007: ldloc.1 
L_0008: ldc.i4.s 10
L_000a: ldc.r8 40000
L_0013: callvirt instance void [mscorlib]Dictionary`2<int32, float64>::Add(!0, !1)
L_0018: nop 
L_0019: ldloc.1 
L_001a: stloc.0 

即。创建分配给临时变量maxDictionary2的字典,填充值,然后只有对创建和填充字典的引用才会复制到maxDictionary变量。

请记住,如果您不想使用parammeterless,可以指定任何其他构造函数。例如。你可以使用一个设置初始容量:

var maxDictionary = new Dictionary<int, double>(10) { { 10, 40000 } };

答案 1 :(得分:7)

var maxDictionary = new Dictionary<int, double> { { 10, 40000 } };

以下是程序生成的IL

IL_0001:  newobj      System.Collections.Generic.Dictionary<System.Int32,System.Double>..ctor
IL_0006:  stloc.1     // <>g__initLocal0
IL_0007:  ldloc.1     // <>g__initLocal0
IL_0008:  ldc.i4.s    0A 
IL_000A:  ldc.r8      00 00 00 00 00 88 E3 40 
IL_0013:  callvirt    System.Collections.Generic.Dictionary<System.Int32,System.Double>.Add
IL_0018:  nop         
IL_0019:  ldloc.1     // <>g__initLocal0
IL_001A:  stloc.0     // maxDictionary

显然,它使用无参数构造函数并调用Add方法。标签“IL_0013”显示对Add方法的调用

等效的c#代码将是

Dictionary<int, double> maxDictionary;
Dictionary<int, double> temp = new Dictionary<int, double>();
temp.Add(10, 40000.0);
maxDictionary = temp;

值得注意的是编译器使用temp变量,我可以看到两个原因

  1. 确保在遇到异常时不会获得半烤字典。
  2. 您不希望编译器只读取字段来创建新实例和分配。不是吗?

答案 2 :(得分:1)

其他人已经指出如何 C#编译器如何发出对Add的{​​{1}}方法的调用。但是,还没有人谈论何时 C#编译器发出这些调用。

好吧,它与Dictionary(或System.Collections.Dictionary)类无关。此功能称为集合初始化,因为它要求目标实例具有实现System.Collections.Generic.Dictionary<TKey, TValue>接口的类型。唯一的要求是存在名为System.Collections.IEnumerable的方法,甚至不会考虑其签名或返回类型。

Add方法只需要一个参数时,初始化看起来像这样:

Add

上面的代码完全表示class Foo : IEnumerable { public void Add(string a) { } public IEnumerator GetEnumerator() { throw new NotImplementedException(); } } var myFoo = new Foo { "item 1", "item 2", "item 3", "item 4", "item 5" }; (或System.Collections.List)类在实现System.Collections.Generic.List<T>时发生的情况。

System.Collections.IEnumerable方法需要两个或更多参数时(例如,对于字典而言),则每个项目都必须具有该方法的每个参数的值,因此它被设计为在括号内包含这些值,并且看起来像这个:

Add
对于好奇的人:

此答案中的代码包含与圈子有关的有趣的事情。有人会发现吗?