用于将对象添加到对象初始化程序中的集合的语法糖

时间:2017-02-01 15:23:47

标签: c# syntax

最近,我遇到了一些看起来像这样的代码:

public class Test
{
    public ICollection<string> Things { get; set; }

    public Test()
    {
        Things = new List<string> { "First" };
    }

    public static Test Factory()
    {
        return new Test
        {
            Things = { "Second" }
        };
    }
}

调用Test.Factory()会产生一个Test个对象,其中Things集合包含"First""Second"

Things = { "Second" }似乎调用Add的{​​{1}}方法。如果Things更改为ICollection,则会出现语法错误,指出&#34; IEnumerable&#34;。

很明显,您只能在对象初始化器中使用这种语法。这样的代码无效:

IEnumerable<string> does not contain a definition for 'Add'

此功能的名称是什么?它引入了哪个版本的C#?为什么它仅在对象初始化器中可用?

2 个答案:

答案 0 :(得分:5)

它被称为collection initializer,它被添加到C# 3 language specifications中(引言中的第7.5.10.3节,当前规范中的第7.6.10.3节)。具体而言,您使用的代码使用嵌入式集合初始值设定项。

集合初始化程序实际上只是调用Add方法,这是根据规范要求的。

Quantic所述,规格说:

  

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

这可以很好地解释你意想不到的结果。

  

为什么它仅在对象初始化程序中可用?

因为它在其他地方没有意义。您可以自己调用Add方法,而不是使用初始值设定项来进行初始化。

答案 1 :(得分:1)

正如帕特里克已经提到的那样,集合初始化程序依次调用列表中的Add。这假定您的属性已由构造函数初始化:

public class MyClass
{
    public List<MyType> TheList { get; private set; }
    public MyClass() 
    {
        this.TheList = new List<MyType>(); 
    }
}

如果没有初始化您的列表的构造函数,您将在以下语句中获得NullReferenceException

test.Things = { "Test" }; 

然而,这与以下内容不同:

var m = new MyClass { TheList = new List<MyType> { ... } };

在这种情况下,您将访问属性 setter 。没有(或者在我的例子中只有private)导致编译器错误。