C# 构造函数如何将值赋值给只读 属性?

How can C# constructor assign value to read only property?

我写了一个只有 get 访问器的 class 属性,比如:

public int MyProp { get; }

我无法通过我的 class 中的方法为 MyProp 分配任何值,即使是私下也不行,也就是说,如果我有一个私有集,那是不一样的。 但是,不知何故,我可以使用如下构造函数为 myProp 设置一个值:

public MyClass (int myProp) { this.MyProp = myProp; }

构造函数是否总是不受 属性 访问器规范的影响?它们只有在构造函数运行后才有效吗?

当您创建一个 auto-属性 时,编译器会自动生成支持字段来支持它。在只读的情况下(仅get)属性,情况仍然如此。能够在构造函数中分配给 get-only 属性 只是编译器支持的 语法糖 。当您分配给 属性 时,编译器会翻译代码,以便它分配给 支持字段

例如,假设您的构造函数:

public MyClass(int myProp)
{ 
    this.MyProp = myProp;
}

编译器将其翻译成类似于以下内容的内容

public MyClass(int myProp)
{ 
    this._myPropBackingField = myProp;
}

您没有 set 访问器的事实会阻止您在其他任何地方分配给 属性。

实际上,支持字段收到一个“无法说出”的名称,该名称是非法的 c#(但有效的 IL),从而阻止 you 尝试直接使用该字段。编译器完成工作后,您的示例实际上如下所示:

public class MyClass
{
    [CompilerGenerated]
    private readonly int <MyProp>k__BackingField;

    public int MyProp
    {
        [CompilerGenerated]
        get
        {
            return this.<MyProp>k__BackingField;
        }
    }

    public MyClass(int myProp)
    {
        this.<MyProp>k__BackingField = myProp;
    }
}

请注意,构造函数实际上是直接而不是通过属性的set之三间接分配给支持字段<MyProp>k__BackingField (毕竟一个都不存在)。

看到这个SharpLab example

试想如果不允许构造函数初始化这些值,那么这些值有什么用呢?它将始终是数据类型的默认值,就像 int 一样,它将是 0。仅使用 get 意味着我们将不允许在初始化后更改该值。

您也可以使用 readonly,默认情况下它是线程安全的。但是当您使用私有集时,您必须显式处理线程安全。