嵌套对象初始化程序似乎无效但可以编译

Nested object initialiser seems invalid but compiles

如果我有以下 属性 没有 setter 或支持字段

public List<string> TestProperty => new List<string> {"one", "two"};

并尝试使用

在对象初始化器中初始化它
TestProperty = new List<string> {"three", "four"}

我得到了预期的错误:

[CS0200] Property or indexer 'X.TestProperty' cannot be assigned to -- it is read only

但是,如果我尝试使用

在对象初始化器中初始化它
TestProperty = { "three", "four" }

编译一切正常,但 属性 仍然 returns new List<string> {"one", "two"};.

@jon-skeet 在 this 回答中解释说第二种形式是 嵌套对象初始化器 但我仍然不确定为什么上面的(无用)编译以及是否可以停止并从对象初始化程序中的 IDE 自动完成 (ReSharper) 中删除 属性?这只会让我的代码的用户感到沮丧。

编辑:请注意,我不想初始化这个 属性,我担心的是编译器允许发生看起来像初始化的事情。

假设你有这个:

public class X 
{
    public List<string> TestProperty => new List<string> {"one", "two"};
}

然后:

public static void Main()
{
    var x = new X 
    {
        TestProperty = { "a", "b" }
    };
}

大致编译为:

var x = new X();
var list = x.TestProperty; // remember, this is a NEW list
list.Add("a");
list.Add("b");

因此,当您打印(或在调试器中查看)时 x.TestProperty,这是一个全新的列表,因此您添加的值实际上被忽略了。

为什么该语法有效?因为该功能的设计使得您通常会在构造函数中生成一个空列表,并且 Add 调用会添加到该列表中。在这种情况下,放弃这些值只是您的决定,因为您可以使用支持字段而不是返回新实例。


@madreflection 通过 this SharpLab 正确指出,每次调用 Add 都会在调用 x.TestProperty 之后完成,因此“a”和“b”将以 2 个不同的形式结束列出。