在基类构造函数中设置时,为什么覆盖的get-only属性保持为null?

时间:2018-11-30 10:49:24

标签: c# automatic-properties

我尝试了以下示例:

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保持为空。但为什么? 我真的不了解它,有人可以向我解释为什么会这样吗?至少我会期望出现一个错误,即无法在所属类的外部设置只读属性。

2 个答案:

答案 0 :(得分:38)

编译器对此进行如下处理;基本上,构造函数中的代码写入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
        }
    }
}

答案 1 :(得分:17)

解释此问题的最简单方法是考虑编译器为实现此目的而生成的代码。

基类与此等效:

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

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

    readonly string _testBaseReadOnly;
}

派生类与此等效:

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

    readonly string _testReadOnly;
}

这里要注意的重要一点是,派生类具有针对ReadOnly的OWN BACKING FIELD-它不会重用基类中的那个。

已经意识到,为什么覆盖属性为null是显而易见的。

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

偶然地,如果您使用的是Resharper,它实际上会警告您没有在派生类中设置ReadOnly

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