【问题标题】:How can C# constructor assign value to read only property?C# 构造函数如何为只读属性赋值?
【发布时间】:2020-07-05 08:00:14
【问题描述】:

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

public int MyProp { get; }

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

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

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

【问题讨论】:

  • 您可以参考这些链接:docs.microsoft.com/en-us/dotnet/csharp/language-reference/… & pluralsight.com/guides/… 了解所有上下文的只读属性。
  • 试想如果不允许构造函数初始化这些值,那么这些值有什么用?它始终是数据类型的默认值,就像 int 一样,它将是 0。通过仅使用 get 意味着我们将不允许在初始化后更改该值
  • 是的,构造函数总是可以在没有 getter 的情况下设置属性。我看到 C# 9 现在有一个 init 关键字:stackoverflow.com/questions/62372422/…
  • 是编译器强制执行这些规则,所以如果编译器有规则允许代码写入只读字段,编译器可以这样做。构造函数受此类规则的约束,C# 9 中的新 init 成员也是如此。

标签: c# class constructor properties accessor


【解决方案1】:

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

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

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

这被编译器翻译成类似于以下的东西

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

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

实际上,支持字段接收到一个“不可描述”的名称,该名称是非法的 c#(但有效的 IL),因此阻止 尝试直接使用该字段。在编译器完成其工作后,您的示例实际上如下所示:

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

请注意,构造函数实际上是直接分配给支持字段&lt;MyProp&gt;k__BackingField,而不是通过属性的setter 间接分配(因为毕竟不存在)。

看到这个SharpLab example

【讨论】:

  • 你的解释是最清楚的。现在很清楚了,谢谢。
【解决方案2】:

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

你也可以使用readonly,默认是线程安全的。但是当你使用私有集合时,你必须明确地处理线程安全。

【讨论】:

    猜你喜欢
    • 2019-02-25
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多