为什么数组初始值设定项不适用于局部变量?

时间:2018-08-24 22:44:35

标签: c#

为什么可以执行以下操作而不会出现编译器错误:

private class Foo
{
     public List<string> Bar { get; set; }
}

private void SomeRandomMethod(){
    var test2 = new Foo
    {
         Bar = { "test", "test2" }
    };
}

但这不起作用吗?

List<string> test = { "test", "test2" };

我确实知道我可以写new { "test", "test2" };,然后它才能工作。我不希望此问题有解决方法或解决方案或类似的方法,相反,我想解释一下这两种情况的确切区别。

编辑:将类型从List<string>更改为string[]时,第一个示例不再编译,而第二个示例编译。

谢谢!

1 个答案:

答案 0 :(得分:4)

这里的困惑来自相同的语法在不同的上下文中被视为不同。在对象初始化程序中,表达式表示集合初始化程序

规范将集合初始化方法定义为:

  

7.6.10.3集合初始化程序

     

集合初始值设定项由一系列元素初始值设定项组成,并用{和}标记括起来并以逗号分隔。每个元素初始化程序都指定一个要添加到要初始化的集合对象中的元素,并由{和}标记括起来并以逗号分隔的一系列表达式组成。

同一章后来:

  

对于按顺序指定的每个指定元素,集合初始化器将目标初始化器的表达式列表作为参数列表,并在目标对象上调用Add方法,并对每个调用应用正常的重载解析。

所以这就是为什么在第一个示例中获得NRE的原因。由于在使用集合初始值设定项之前未添加new List<string>,因此您尝试在Add对象上调用null。您将需要添加new List<string>或在构造函数中执行。

数组初始化器是不同的,当您省略new时,编译器会为您添加新的变量,因此:

string[] values = { "foo", "bar" };

等效于:

string[] values = new [] { "foo", "bar" };

在对象初始值设定项之外使用{ "foo", "bar" }时,会出现错误,因为您试图将数组分配给列表。

注意:在集合初始值设定项中,您可能希望编译器更智能,并像在数组初始值设定项中那样为您添加new,但可能会有其他副作用。例如,如果要在构造函数中初始化列表,它将覆盖该列表。所以我想这就是原因。