【问题标题】:Nested object initialiser seems invalid but compiles嵌套对象初始化器似乎无效但可以编译
【发布时间】:2021-01-28 06:04:41
【问题描述】:

如果我有以下没有设置器或支持字段的属性

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" }

一切编译正常,但该属性仍返回 new List&lt;string&gt; {"one", "two"};

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

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

【问题讨论】:

  • 好吧,TestProperty 确实返回了一个初始化的List&lt;T&gt;,因此您可以安全地向其中添加数据。数据不分配给TestProperty 只是您的决定。
  • 请注意,x.TestProperty == x.TestProperty 会给你一个惊喜。创建一个新集合通常应该是一个方法而不是一个属性。
  • 除此之外,在这个问题中出现类似问题对于公共 API 来说是一个糟糕的选择
  • @CamiloTerevinto“属性已初始化”通常意味着“有一个值分配给一个属性一次并且它保持这种方式(直到新的分配)”,您在“属性”的不太常见的意义上使用它总是返回一个非空值”...
  • 我完全理解这个属性是一个没有设置器的计算属性。我试图理解为什么在对象初始化程序中允许使用该语法以及它在做什么......

标签: c# initializer


【解决方案1】:

假设你有这个:

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”最终会出现在两个不同的列表中。

【讨论】:

  • 我会接受这一点,但添加此语法“添加”到(在这种情况下为计算的)值而不是“设置”它可能会有所帮助。因此,没有 setter 不是问题。
  • 感谢大家的帮助,不胜感激!
猜你喜欢
  • 2013-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-19
  • 2021-07-31
相关资源
最近更新 更多