You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:35:43