在对象初始值设定项中使用数组初始值设定项时的NRE

在以下情况中使用数组初始值设定项时,我观察到一些奇怪的行为(在VS2013中测试过):

class A { public List Items { get; set; } } void Main(string[] args) { // (1) it compiles, but failing with NRE in runtime var a = new A { Items = { 1, 2, 3 } }; // (2) it does not compile, as expected List b = { 1, 2, 3 }; } 

实际上我会期望在情况(1)中出现编译器错误,与我在情况(2)中的情况相同: Can only use array initializer expressions to assign to array types. Try using a new expression instead. Can only use array initializer expressions to assign to array types. Try using a new expression instead. 但是case(1)编译时没有任何问题,并且在运行时可以预期NullReferenceException失败。 有人可以解释为什么编译器允许这种情况(1)?

以下是C#规范的相关引用(第5版,第7.6.10.2节):

在等号后面指定集合初始值设定项的成员初始值设定项是嵌入式集合的初始化。 而不是将新集合分配给字段或属性,初始化程序中给出的元素将添加到字段或属性引用的集合中。 字段或属性必须是满足§7.6.10.3中指定要求的集合类型。

因为你在对象初始化器中使用了一个集合初始化 ,行为是不同的,这段代码:

 var a = new A { Items = { 1, 2, 3 } }; 

编译成这样的东西(你可以通过查看IL来validation这一点):

 var a = new A(); a.Items.Add(1); a.Items.Add(2); a.Items.Add(3); 

这当然会抛出NullReferenceException,因为Items为null。

您可以通过向A类添加构造函数来修复崩溃:

 class A { public List Items { get; set; } public A() { Items = new List(); } }