【发布时间】:2014-01-24 12:52:53
【问题描述】:
var maxDictionary = new Dictionary<int, double> { { 10, 40000 } };
在上面的代码中,编译器是否使用了构造函数?或者编译器是否创建一个 KeyValuePair 并添加到字典中?我试图了解编译器是如何解释它的。
【问题讨论】:
标签: c# dictionary constructor
var maxDictionary = new Dictionary<int, double> { { 10, 40000 } };
在上面的代码中,编译器是否使用了构造函数?或者编译器是否创建一个 KeyValuePair 并添加到字典中?我试图了解编译器是如何解释它的。
【问题讨论】:
标签: c# dictionary constructor
是的,编译器使用默认的无参数构造函数,然后通过Dictionary.Add 方法添加集合初始化程序中指定的所有值。正如乔恩指出的那样,您的代码被编译成
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变量。
请记住,如果您不想使用无参数构造函数,则可以指定任何其他构造函数。例如。你可以使用一个设置初始容量的:
var maxDictionary = new Dictionary<int, double>(10) { { 10, 40000 } };
【讨论】:
maxDictionary 的分配发生在 Add 调用之后。如果您实际上是重新分配给现有变量,则这是可见的,其中集合初始化程序可以使用现有变量的值,并且它引用 old 集合。
foreach循环而不是直接调用GetEnumerator()等。
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 变量,我可以看到两个原因
【讨论】:
其他人已经指出 C# 编译器如何发出对Dictionary 的Add 方法的调用。但是,仍然没有人谈论何时 C# 编译器发出这些调用。
嗯,它与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 方法需要两个或更多参数时,就像字典一样,那么每个项目都必须具有该方法的每个参数的值,因此它被设计为将这些值包含在大括号中,如下所示:
class Foo : IEnumerable
{
public void Add(string a, int b, bool c)
{
}
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
var myFoo = new Foo
{
{ "item 1", 3, false },
{ "item 2", 1, true },
{ "item 3", 4, true },
{ "item 4", 1, true },
{ "item 5", 5, true },
};
对于好奇的人:
这个答案中的代码包含一个与圈子相关的有趣的东西。会有人发现它吗?
【讨论】: