C# 为什么允许我修改对象初始值设定项为只读的属性?

C# 为什么允许我修改对象初始值设定项为只读的属性?,c#,properties,getter-setter,object-initializers,collection-initializer,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<Stri

我有一个简单的代码:

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() { }
}
列表中填充了字符串“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
而不是
string2
tmp.List
返回
string1
。您从不分配属性,只需初始化返回的集合。因此,您应该在这里查看getter,而不是setter


然而,Tim是绝对正确的,因为以这种方式定义的属性没有任何意义。这违反了最小惊奇原则,对于该类的用户来说,setter在那里发生了什么并不明显。不要这样做。

这就是集合初始值设定项在内部的工作方式:

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;
\u d.List
在getter中使用
string1

[*]更多详细信息,请参见C#规范$
7.6.10.3集合初始值设定项


将代码更改为:

Data data = new Data { List = new List<string>{ "1", "2", "3", "4" } };
Data Data=新数据{List=新列表{“1”、“2”、“3”、“4”};

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

您将元素添加到
List string2
中,然后您正在阅读
List string1
对我来说毫无意义。但是列表string2在添加elementsHow之后是epmty,您知道吗??您没有在代码中的任何地方检查
列出string2
。@kevintjuh93:看看代码,很明显
string2
必须是空的。哦,是的,忘了它被转换为
Add
,它使用
get
当然,它不是用于真正任务的代码,我只是想知道事情是如何运作的=)@Asbrand:如果你对事情的运作方式感兴趣,我建议你下载并插入编译器输出。或者阅读C#规范。当然,两者都需要一点时间来适应,但作为学习资源,它们是无价的。@Joey:我也会使用反编译器,而不是反编译器。注意,我同时删除了我的答案。@Tim:实际上两者都是。反编译器非常精确地告诉您编译器对您编写的代码所做的操作。参考源用于澄清框架中发生了什么。当然,从历史上看,第二点也是由反编译器来回答的。@Asbrand这就是它真正的功能,我反编译了你的样本,它完全按照@Joey说的做。唯一的区别是它没有使用
tmp
,但在
数据
更改时,所有操作都会立即完成。您的代码部分将抛出异常
属性或indexer“Program.data.List”无法分配给它--它是只读的
,这实际上是混淆为什么没有setter的属性看起来首先是可设置的原因。@Sinatr,Tim Schmelter!选中“编辑历史记录”。我应该同意,第二个例子在编辑后不起作用
Data _d = new Data();
_d.List.Add("1");
_d.List.Add("2");
_d.List.Add("3");
_d.List.Add("4");
Data data = _d;
Data data = new Data { List = new List<string>{ "1", "2", "3", "4" } };