Syntactic sugar for adding items to collections in object initialisers
最近,我遇到了一些类似这样的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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" }调用了Things的Add方法。如果将ICollection改为IEnumerable,则会出现语法错误,说明"IEnumerable does not contain a definition for 'Add'"。
很明显,在对象初始化器中只能使用这种语法。此类代码无效:
1 2
| var test = new Test ();
test .Things = {"Test" }; |
此功能的名称是什么?它是在哪个版本的C中引入的?为什么它只在对象初始化器中可用?
- 我敢打赌它是在C 6.0中引入的,但我找不到任何关于它的信息。
- 它被称为集合初始值设定项,我很确定它早于C 6,但不能准确地分辨。
- geekswithblogs.net/blackrabbitcoder/archive/2015/05/08/&hellip;-是C 6.0
- stackoverflow.com/questions/459652/&hellip;
- stackoverflow.com/questions/2495791/&hellip;
- 我不认为它是集合初始化器,因为主题的msdn页面(以及我找到的所有其他源)没有演示语法Things = {"Second" }。在每个示例中,第一个{前面都有new关键字,表示一个全新的对象。
- 它和我的VS2010一起工作,所以它已经和C 3一起工作了。将我的语言版本从C 3更改为ISO-2会导致许多编译器错误:Feature 'collection initializer' cannot be used because it is not part of the ISO-2 C# language specification因此被添加到C 3。
- @概要的,然后你看的是对象初始值设定项,而不是集合初始值设定项。
- @如果你把Things = new List {"First" };改成Things = new List();呢?
- 所以在这种情况下,=是"添加"而不是"设置"?我不喜欢-很困惑。
它被称为集合初始值设定项,并被添加到C_3语言规范中(在引言部分的第7.5.10.3节,在当前规范中的第7.6.10.3节)。具体来说,使用的代码使用嵌入的集合初始值设定项。
集合初始值设定项实际上只是调用Add方法,这是根据规范所必需的。
正如Quantic所评论的,规范说:
0
这就很好地解释了你意想不到的结果。
Why is it only available in object initialisers?
因为其他地方没有意义。您可以自己调用Add方法,而不是为初始化以外的东西使用初始值设定项。
- 为了完整起见,要查看的当前规范(版本5.0)的节号是7.6.10.3。
- 语法Things = {"Second" }更具体地说是"嵌入集合初始值设定项",如规范中所述:"在等号后面指定集合初始值设定项的成员初始值设定项是嵌入集合的初始化。不是为字段或属性分配新集合,而是将初始值设定项中给定的元素添加到字段或属性引用的集合中"。我所看到的这种语法的最接近的例子是在规范的同一部分,但对于"嵌套对象初始值设定项":P1 = { X = 0, Y = 1 }。
- 的确,更新了good catch@quantic!
- 谢谢你@quantic这正是我要找的
正如Patrick已经提到的,集合初始值设定项顺序调用列表中的Add。这假定您的属性已由构造函数相应地初始化:
1 2 3 4 5 6 7 8
| public class MyClass
{
public List <MyType > TheList { get; private set; }
public MyClass ()
{
this.TheList = new List <MyType >();
}
} |
如果没有这样的构造函数初始化您的列表,您将在下面的语句中得到一个NullReferenceException:
1
| test.Things = {"Test" }; |
但是,这与以下不同:
2
在这种情况下,您将访问属性setter。如果没有(或者只有我的示例中的private一个),则会导致编译器错误。