为什么我允许使用对象初始化程序修改只读的属性?

时间:2015-10-09 12:00:17

标签: c# properties getter-setter object-initializers collection-initializer

我有这个简单的代码:

public static void Main(String[] args)
{
    Data data = new Data { List = { "1", "2", "3", "4" } };
    foreach (var str in data.List)
        Console.WriteLine(str);
    Console.ReadLine();
}

public class Data
{
    private List<String> _List = new List<String>();
    public List<String> List
    {
        get { return _List; }
    }
    public Data() { }
}

所以当我创建一个Data类时:

Data data = new Data { List = { "1", "2", "3", "4" } };

即使没有set,该列表也填充了字符串“1”,“2”,“3”,“4”。

为什么会这样?

2 个答案:

答案 0 :(得分:11)

您的对象初始值设定项(包含List的集合初始值设定项)

Data data = new Data { List = { "1", "2", "3", "4" } };

变成了以下内容:

var tmp = new Data();
tmp.List.Add("1");
tmp.List.Add("2");
tmp.List.Add("3");
tmp.List.Add("4");
Data data = tmp;

以这种方式看待它应该很清楚为什么你实际上是string1而不是string2tmp.List 返回 {{ 1}}。您永远不会分配给属性,只需初始化返回的集合。因此,你应该在这里看看getter,而不是setter。

然而,Tim绝对正确,因为以这种方式定义的属性没有任何意义。这违反了最不惊讶的原则,并且对于那个类的用户而言,那里的设置者所发生的事情一点也不明显。不要做这些事情。

答案 1 :(得分:4)

这就是集合初始化程序在内部的工作方式:

Data data = new Data { List = { "1", "2", "3", "4" } };

基本上等于

Data _d = new Data();
_d.List.Add("1");
_d.List.Add("2");
_d.List.Add("3");
_d.List.Add("4");
Data data = _d;

_d.List在getter中使用string1

[*] C#规范$ 7.6.10.3 Collection initializers

中的更多详细信息

将您的代码更改为:

Data data = new Data { List = new List<string>{ "1", "2", "3", "4" } };

string1将为空,string2将有四个项目。