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