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

在C#中实现父类可调用的抽象类属性重写的最优方案

在C#中实现子类重写父类属性的更优方案

在不少编程语言里,继承抽象类时可以直接重写类的属性字段,父类方法调用时会自动读取子类的新值,示例如下:

abstract class A {
    protected string foo;
    
    void PrintFoo() {
        print(foo);
    }
}

class B extends A {
    protected string foo = "bar";
}

(new B()).PrintFoo(); // outputs: bar

但这种写法在C#里无法直接实现,下面先梳理已尝试的几种方案,再讨论更优实现:

已尝试的实现方案

方法一:构造函数传参

通过子类构造函数向父类构造函数传递参数初始化字段,代码如下:

abstract class A {
    protected string foo;
    public A(string foo) {
        this.foo = foo;
    }

    void PrintFoo() {
        Console.WriteLine(foo);
    }
}

class B : A {
    public B() : base("bar") {}
}

(new B()).PrintFoo(); // outputs: bar

这种方式的缺点是不够简洁,每个子类都得在构造函数里显式传参。

方法二:虚属性重写

定义虚属性,子类重写属性的取值逻辑,代码如下:

abstract class A {
    protected virtual string Foo { get; }

    void PrintFoo() {
        Console.WriteLine(Foo);
    }
}

class B : A {
    protected override string Foo {
        get { return "bar"; }
    }
}

(new B()).PrintFoo(); // outputs: bar

这种方式更符合面向对象的多态设计,但写法还有简化空间。

简化版:表达式体属性

利用C#的表达式体语法进一步简化代码:

abstract class A
{
    public virtual string Foo => null;
}
class B : A
{
    public override string Foo => "bar";
}

更优的实现方式

如果追求极致简洁且贴合C#的设计习惯,表达式体的虚属性重写已经是当前比较优的方案,它兼顾了多态特性和代码简洁性。

另外,如果父类本身就要求子类必须提供该属性的值,可以把父类的属性定义为abstract,这样子类必须强制实现,语义更清晰,写法也更简洁:

abstract class A
{
    protected abstract string Foo { get; }

    void PrintFoo()
    {
        Console.WriteLine(Foo);
    }
}

class B : A
{
    protected override string Foo => "bar";
}

这种方式省去了父类的默认实现,还能避免子类忘记重写导致的默认值问题,完全贴合抽象类的设计初衷。

如果子类的属性值是编译期常量,也可以结合const使用,但要注意const是静态成员,不能用于虚属性重写;如果是实例级的固定值,表达式体属性已经足够简洁。

内容的提问来源于stack exchange,提问作者maduranma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 08:56:04