无setter的抽象属性无法在构造函数赋值?与普通属性差异解析
抽象只读属性 vs 普通只读自动属性:构造函数赋值差异解析
这问题问得很到位,其实核心是抽象属性和普通自动实现属性在底层本质上的不同,咱们结合你的代码一步步说:
1. 普通只读自动属性为啥能在构造函数里赋值?
你写的public double CubicCentimeters { get; }是C#的自动实现属性,编译器在编译时会偷偷帮你做这些事:
- 生成一个私有的幕后字段(比如
<>k__BackingField这类编译器自动命名的字段); - 把
get访问器实现为返回这个幕后字段; - 关键在于:构造函数里的
this.CubicCentimeters = cubicCentimeters,编译器会直接把它转换成给那个私有幕后字段赋值——相当于绕开了get访问器,直接操作底层存储。
因为构造函数是对象初始化的特殊阶段,编译器允许这种直接操作幕后字段的行为,所以你不会收到报错。
2. 抽象只读属性为啥不能这么干?
再看你的public abstract int HorsePower { get; },抽象属性本质上只是一个契约:它要求所有派生类必须实现这个get访问器,但它自己没有任何底层存储(幕后字段)。
当你在基类构造函数里写this.HorsePower = horsePower时,编译器根本不知道该把值存在哪里——这个属性的具体实现是派生类要完成的事,基类里没有对应的字段可以接收这个值。所以编译器直接报错,告诉你它是只读的,无法赋值。
3. 怎么解决这个问题?
如果想在基类构造函数里给抽象属性对应的“值”初始化,有两种常见方案:
方案一:给抽象属性添加protected setter
public abstract int HorsePower { get; protected set; }
这样基类构造函数里就能调用set访问器赋值,派生类也可以根据需要重写或使用这个setter(如果不想让派生类修改,也可以把setter设为private)。
方案二:基类定义受保护的幕后字段,抽象属性返回它
protected int _horsePower; public abstract int HorsePower { get; } // 构造函数里直接给字段赋值 protected Motorcycle(int horsePower, double cubicCentimeters) { this._horsePower = horsePower; this.CubicCentimeters = cubicCentimeters; }
然后派生类的HorsePower实现就返回这个字段:
public class SportBike : Motorcycle { public override int HorsePower => _horsePower; }
核心总结
- 普通只读自动属性:编译器生成幕后字段,构造函数赋值是直接操作字段,被允许;
- 抽象只读属性:无底层存储,只是一个必须实现的get契约,基类构造函数没有可赋值的目标,因此报错。
内容的提问来源于stack exchange,提问作者Kite
相关产品推荐
相关产品推荐

