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

C#继承中子类修改父类protected字段的逻辑疑问

C#继承中同名字段的隐藏问题解析

你遇到的问题核心是子类字段隐藏了父类的同名字段,这和方法的覆盖(override)逻辑完全不同,具体原因拆解如下:

1. 字段没有“覆盖”,只有“隐藏”

C#中,字段不支持像虚方法那样的覆盖机制。当子类定义了和父类同名的字段时,子类字段会隐藏父类的同名字段——相当于两个完全独立的字段,只是名字一样:

  • 父类Member的protected int annualFee是父类自己的字段,默认值为0(int类型默认值)。
  • 子类VIPMember的public int annualFee = 120000是子类自己的字段,初始值设为120000。

2. 子类方法中访问同名字段的默认行为

在子类的CalculateAnnualFee方法里,你写的annualFee = 1200 * 2 + 12 * 30;,默认访问的是子类自己的字段,而不是父类的。所以这行代码把子类的annualFee从120000改成了2760,但父类的annualFee始终没被赋值,还是默认的0。

3. 父类方法只能访问自己的字段

父类Member的ToString方法属于父类,它只能访问父类自己的annualFee字段,所以输出的是0,而不是子类字段的值。

4. 外部访问子类实例的字段时的行为

测试代码中myChildMember2.annualFee直接访问的是子类的字段,所以显示的是被CalculateAnnualFee修改后的2760,而不是初始的120000。


修正方案

如果你想让父类的ToString输出计算后的年费,同时保持子类对外暴露字段的需求,可以这么改:

方案1:移除子类的同名字段,直接使用父类字段

class VIPMember : Member
{ 
    public VIPMember(string name, int memberId, int memberSince) : base (name, memberId, memberSince)
    {
        Console.WriteLine("Child constructor with 3 paramemters");
    }

    public void CalculateAnnualFee()
    {
        annualFee = 1200 * 2 + 12 * 30; // 此时访问的是父类的protected字段
    }

    // 如果需要对外公开父类的annualFee,用属性包装
    public int AnnualFee => annualFee;
}

方案2:明确区分父类和子类字段(不推荐,易混淆)

如果一定要保留子类的同名字段,需要在代码中明确指定访问父类还是子类的字段:

class VIPMember : Member
{ 
    public VIPMember(string name, int memberId, int memberSince) : base (name, memberId, memberSince)
    {
        Console.WriteLine("Child constructor with 3 paramemters");
    }

    public void CalculateAnnualFee()
    {
        base.annualFee = 1200 * 2 + 12 * 30; // 给父类字段赋值
        this.annualFee = 120000; // 保留子类字段初始值
    }

    public int annualFee = 120000;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:12:23