为什么重写的 get-only 属性 在 base class 构造函数中设置时保持为空?

Why does an overridden get-only property stay null when set in base class constructor?

我尝试了以下示例:

public class TestBase
{
    public virtual string ReadOnly { get; }

    public TestBase()
    {
        ReadOnly = "from base";
    }
}

class Test : TestBase
{
    public override string ReadOnly { get; }
    public Test()
    {
        // nothing here
    }
}

当我创建一个 Test 实例时,我看到 ReadOnly 保持为空。但为什么? 我真的不明白它的窍门,有人可以向我解释为什么会这样吗?至少我会期待一个错误,即只读 属性 不能设置在拥有 class.

之外

解释这一点的最简单方法是考虑编译器生成什么代码来实现它。

基数 class 等同于:

public class TestBase
{
    public virtual string ReadOnly => _testBaseReadOnly;

    public TestBase()
    {
        _testBaseReadOnly = "from base";
    }

    readonly string _testBaseReadOnly;
}

导出的class等同于:

class Test : TestBase
{
    public override string ReadOnly => _testReadOnly;

    readonly string _testReadOnly;
}

这里要注意的重要一点是,派生的 class 有自己的 ReadOnly 支持字段 - 它不会重复使用基础 class 中的那个。

意识到这一点后,重写的 属性 为空的原因就很明显了。

这是因为派生的 class 有自己的 ReadOnly 支持字段,并且其构造函数没有初始化该支持字段。

顺便说一下,如果你使用 Resharper 它实际上会警告你你没有在派生的 class:

中设置 ReadOnly
 "Get-only auto-property 'ReadOnly' is never assigned."

编译器如下处理;基本上,构造函数中的代码写入 TestBase 中的 原始 支持字段。看来你的场景不支持,但是……不知道语言组有没有考虑过这种情况。

顺便说一句:如果您想查看编译器对代码做了什么:sharplab.io

public class TestBase
{
    [CompilerGenerated]
    private readonly string <ReadOnly>k__BackingField; // note: not legal in "real" C#

    public virtual string ReadOnly
    {
        [CompilerGenerated]
        get
        {
            return <ReadOnly>k__BackingField; // the one in TestBase
        }
    }

    public TestBase()
    {
        <ReadOnly>k__BackingField = "from base";
    }
}
internal class Test : TestBase
{
    [CompilerGenerated]
    private readonly string <ReadOnly>k__BackingField;

    public override string ReadOnly
    {
        [CompilerGenerated]
        get
        {
            return <ReadOnly>k__BackingField; // the one in Test
        }
    }
}