对象初始值设定项中的只读字段

Her*_*ton 8 c# readonly

我想知道为什么不可能做到以下几点:

struct TestStruct
{
    public readonly object TestField;
}

TestStruct ts = new TestStruct {
    /* TestField = "something" // Impossible */
};
Run Code Online (Sandbox Code Playgroud)

对象初始值设定项是否应该能够设置字段的值?

Xeu*_*ron 14

C# 9 Init-Only Properties(尽管名称如此)将允许初始化语法也能够设置只读字段

\n

以下是从链接复制的相关部分。

\n

仅限初始化的属性

\n

这是对象初始值设定项的一个简单示例。

\n
new Person\n{\n    FirstName = "Scott",\n    LastName = "Hunter"\n}\n
Run Code Online (Sandbox Code Playgroud)\n

今天的一大限制是属性必须是可变的,对象初始值设定项才能工作:它们的功能是首先调用 object\xe2\x80\x99s 构造函数(在本例中是默认的无参数构造函数),然后分配给属性设置器。

\n

仅初始化属性可以解决这个问题!他们引入了一个init访问器,它是访问器的变体set,只能在对象初始化期间调用:

\n
public class Person\n{\n    public string FirstName { get; init; }\n    public string LastName { get; init; }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

通过此声明,上面的客户端代码仍然合法,但任何后续对FirstNameLastName属性的赋值都是错误的。

\n

初始化访问器和只读字段

\n

因为init访问器只能在初始化期间调用,所以它们可以改变readonly封闭类的字段,就像在构造函数中一样。

\n
public class Person\n{\n    private readonly string firstName;\n    private readonly string lastName;\n    \n    public string FirstName \n    { \n        get => firstName; \n        init => firstName = (value ?? throw new ArgumentNullException(nameof(FirstName)));\n    }\n    public string LastName \n    { \n        get => lastName; \n        init => lastName = (value ?? throw new ArgumentNullException(nameof(LastName)));\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n


Mic*_*Liu 10

readonly表示该字段只能在构造函数(或字段初始值设定项)中设置.在构造函数返回设置对象初始值设定项中指定的属性.那是,

TestStruct ts = new TestStruct {
    TestField = "something"
};
Run Code Online (Sandbox Code Playgroud)

基本上相当于

TestStruct ts = new TestStruct();
ts.TestField = "something";
Run Code Online (Sandbox Code Playgroud)

(在Debug构建中,编译器可能会使用临时变量,但您可以理解.)


Hab*_*bib 9

对象初始化程序在内部使用临时对象,然后将每个值分配给属性.拥有一个只读字段会破坏它.

以下

TestStruct ts = new TestStruct 
{
     TestField = "something";
};
Run Code Online (Sandbox Code Playgroud)

会翻译成

TestStruct ts;
var tmp = new TestStruct();
tmp.TestField = "something"; //this is not possible
ts = tmp;
Run Code Online (Sandbox Code Playgroud)

(这是Jon Skeet解释临时对象与对象初始化器的用法答案,但有不同的情况)

  • @siride,我不认为它无关紧要.ReadOnly字段应该在Constructor中赋值,或者使用声明.在对象初始化程序中不允许它的原因是它在内部使用临时对象,然后为每个属性分配一个值.这将破坏简单的C#概念,即在使用前不分配只读字段. (2认同)
  • 不,它不被允许的真正原因是该对象已经被构造,并且一旦构造了一个对象,就不能改变只读字段.请注意,即使使用临时对象,它也是设置了属性/字段的临时对象,因此问题显然与临时对象无关. (2认同)