C#中带get/set的虚属性仅重写getter仍可赋值?原因解析
这个问题涉及到C#属性重写机制里一个容易混淆的细节,我来一步步拆解清楚:
1. 为什么child.Property = true;能正常执行?
当你在Child类中重写Property时,只定义了get访问器,但并没有重写或隐藏父类的set访问器。因为父类的Property是virtual修饰的,子类会自动继承父类的set访问器实现——也就是说,Child类的Property实际上依然拥有可调用的set方法,只是你没有在子类代码中显式重写它而已。
执行child.Property = true;时,编译器会调用父类Parent中定义的set访问器,修改父类内部维护的属性值(编译器会为自动属性生成隐藏字段),所以赋值操作完全合法。
2. 为什么IDE会显示重写后的属性为“只读”?
这是IDE(比如Visual Studio、Rider)的智能提示逻辑导致的差异。当IDE检查Child类的Property定义时,看到你只显式实现了get访问器,没有写set,就会直观标记它为“只读”——但这只是基于你写的代码的表面判断,没有考虑到子类从父类继承来的set访问器。
简单来说,IDE的提示是“代码写法层面”的直观反馈,而实际编译行为是“继承机制层面”的逻辑,两者在这里出现了认知差。
3. 为什么你觉得只有调用base.Property的getter才允许这种写法?
其实这个观察有个小误区——即使你在子类的getter里不调用base.Property,赋值操作依然是合法的。比如把Child的getter改成:
public override bool Property { get => true; }
此时执行child.Property = true;仍然能编译通过,只是调用get时永远返回true,但set操作确实会执行(父类的属性值会被修改,只是子类getter没有暴露这个变化)。
你之所以有这个感受,可能是因为当子类getter调用base.Property时,赋值后的结果能通过getter直接体现出来(比如赋值true后,child.Property会返回true),而如果不调用base,赋值的效果被getter掩盖了,看起来好像赋值没生效,但实际上setter已经正常执行了。
核心逻辑总结
- 子类重写属性时,只需要重写需要修改的访问器,未重写的访问器会继承父类的
virtual实现 - IDE的“只读”提示是基于子类显式代码的判断,不代表实际编译后的运行行为
- 赋值操作是否合法,取决于父类是否提供了可访问的
set访问器,且子类没有通过new关键字隐藏它
内容的提问来源于stack exchange,提问作者rory.ap

