5

在使用 List 作为属性初始化类时,我目睹了一些奇怪的事情。这样做时

var stuff = new Stuff(){list = {1, 2, 3} };

它编译并崩溃说该列表为空。因此,将其添加到 Stuff 的构造函数中:

public Stuff(){
    list = new List<int>();
}

List 现在被初始化为包含{1, 2, 3}这似乎是有道理的。但是,将构造函数更改为

public Stuff(){
    list = new List<int>(){1, 2, 3};
}

像这样初始化

var stuff = new Stuff(){list = {4, 5, 6} };

list 被初始化为包含{1, 2, 3, 4, 5, 6}让我很困惑。

看起来这要么不应该编译,要么不应该这样。这里到底发生了什么?

4

2 回答 2

3

看起来这要么不应该编译,要么不应该这样。这里到底发生了什么?

集合初始化器通过调用.Add传入初始化器的每个项目的方法来工作。这会将它们添加到您在构造函数中预先填充的项目中。

这在Collection Initializers 的文档中进行了解释:

集合初始值设定项允许您在初始化实现 IEnumerable 的集合类时指定一个或多个元素初始值设定项。元素初始值设定项可以是简单值、表达式或对象初始值设定项。通过使用集合初始化器,您不必在源代码中指定对类的 Add 方法的多次调用;编译器添加调用。

这意味着编译器会将您的第二次调用转换为类似于:

var temp = new Stuff();
temp.list.Add(4);
temp.list.Add(5);
temp.list.Add(6);
Stuff stuff = temp;

如您所见,该stuff变量将正常调用构造函数(添加123),然后添加其他项,从而得到您所看到的。

于 2013-10-30T21:58:47.323 回答
3

您正在list使用集合初始化程序进行初始化。这种工作方式在文档中给出:

集合初始值设定项允许您在初始化实现的集合类时指定一个或多个元素初始值设定项 IEnumerable。元素初始值设定项可以是简单值、表达式或对象初始值设定项。通过使用集合初始化器,您不必Add在源代码中指定对类方法的多次调用;编译器添加调用。

换句话说,这:

var stuff = new Stuff(){list = {1, 2, 3} };

是写这个的简写方式:

var temp = new Stuff();
temp.list.Add(1);
temp.list.Add(2);
temp.list.Add(3);
stuff = temp;

很容易看出这将如何导致NullReferenceExceptionif listisnull以及它如何附加到列表中的现有项目(如果有)。

于 2013-10-30T21:59:32.080 回答