这段代码如何设置一个只读 属性?

How is this code able to set a get-only property?

classJsonSerializerOptions有以下属性:

public IList<Serialization.JsonConverter> Converters { get; }

这段代码工作正常,符合预期:

using System.Text.Json.Serialization;

var options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter());

如预期的那样,此代码失败:

var options = new JsonSerializerOptions
{
    Converters = new List<JsonConverter> { new JsonStringEnumConverter() }
};

// `Property or indexer 'JsonSerializerOptions.Converters' cannot be assigned to -- it is read only`

到目前为止,还不错。但令我惊讶的是,这段代码也能正常工作:

var options = new JsonSerializerOptions
{
    Converters = { new JsonStringEnumConverter() }
};

最后一个例子到底发生了什么?我可能有精神失误,但我认为我以前没有遇到过这样的语法。有人可以指出记录在哪里吗?而且我不明白为什么它能够绕过 属性 缺少 setinit.

旁注:我询问的代码基于 this article

What exactly is happening in that last example? I might be having a mental lapse, but I don't think I've encountered such syntax before. Can someone point out where it is documented?

这是集合初始化语法。已记录 here. And more directly with regards to read-only props here.

Some classes may have collection properties where the property is read-only...You will not be able to use collection initializer syntax discussed so far since the property cannot be assigned a new list. However, new entries can be added nonetheless using the initialization syntax by omitting the list creation.

此语法适用于 'collection types that implement IEnumerable and has Add with the appropriate signature as an instance method or an extension method.'

要深入阅读,请查看 the spec 更准确地说:

The collection object to which a collection initializer is applied shall be of a type that implements System.Collections.IEnumerable or a compile-time error occurs. For each specified element in order, normal member lookup is applied to find a member named Add. If the result of the member lookup is not a method group, a compile-time error occurs. Otherwise, overload resolution is applied with the expression list of the element initializer as the argument list, and the collection initializer invokes the resulting method. Thus, the collection object shall contain an applicable instance or extension method with the name Add for each element initializer.

这是 C# 中存在的一种非常晦涩的语法,但知道它的人并不多。

最后一个例子中的代码实际上等同于:

var options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter());

它不会分配给 Converters 属性,而是只会将值插入到列表中。