我尝试了以下示例:
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保持为null。但为什么呢?我真的不明白,有人能解释一下为什么会发生这种事吗?至少我预计会出现一个错误,即不能在所属类之外设置只读属性。
编译器如下处理;基本上,构造函数中的代码写入TestBase
中的原始备份字段。你的场景似乎不受支持,但是。。。我想知道语言团队是否考虑过这个案例。
BTW:如果你想看看编译器对代码做了什么: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
}
}
}
解释这一点的最简单方法是考虑编译器正在生成什么代码来实现它。
基类相当于:
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
有自己的BACKING字段——它不会重用基类中的那个字段。
意识到这一点后,应该很清楚为什么被重写的属性为null。
这是因为派生类有自己的ReadOnly
支持字段,而它的构造函数没有初始化该支持字段。
顺便说一句,如果您使用Resharper
,它实际上会警告您没有在派生类中设置ReadOnly
"Get-only auto-property 'ReadOnly' is never assigned."