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

C#继承问题:调用派生类对象的继承方法时误用基类变量

问题分析与解决方案:子类字段未被父类方法访问的问题

咱们直接点出核心问题:你遇到的「方法调用用了父类字段而非子类值」「CS0414字段未使用警告」,本质是同一个原因——字段访问权限错误+重复声明导致的字段隐藏。

问题根源拆解

  1. 父类字段是私有(private)的:Kingdom里的milk、wings、fruits是私有字段,子类Plant、Animelia、Mamalia根本无权访问这些字段。
  2. 子类重复声明私有字段:你在每个子类里又重新定义了同名的私有字段,相当于每个子类都有一套独立的milk/wings/fruits,但父类的Fly、Milk、Fruit方法只会访问自己类里的私有字段,完全碰不到子类的这些字段。这就导致子类的字段只被赋值却从未被使用,触发CS0414警告;同时运行时调用方法,用的都是父类字段的初始值,不是你子类设置的预期值。

解决方案:正确复用父类字段

我们需要让子类能修改父类的字段,同时去掉子类里重复的字段声明。这里有两种简洁的实现方式:

方式1:将父类字段改为protected,子类直接赋值

把Kingdom的字段改成protected(受保护权限,子类可直接访问),子类去掉重复的私有字段,在构造函数里直接给父类的字段赋值即可。

修正后的完整代码:

class Kingdom 
{ 
    // 把private改为protected,允许子类访问
    protected bool milk, wings, fruits; 

    public Kingdom() : this(true, true, true) {} 
    public Kingdom(bool m, bool w, bool f) 
    { 
        milk = m; 
        wings = w; 
        fruits = f; 
    } 

    public virtual string me() { return "Kingdom Member"; } 

    public virtual void Fly() 
    { 
        if(this.wings) { Console.WriteLine(me() + " may Fly."); } 
        else { Console.WriteLine(me() + " can not Fly."); } 
    } 

    public virtual void Fruit() 
    { 
        if(this.fruits) { Console.WriteLine(me() + " may bear Fruits."); } 
        else { Console.WriteLine(me() + " can not bear Fruits."); } 
    } 

    public virtual void Milk() 
    { 
        if(this.milk) { Console.WriteLine(me() + " may produce milk."); } 
        else { Console.WriteLine(me() + " can not produce milk."); } 
    } 
} 

class Plant : Kingdom 
{ 
    // 删除重复的私有字段
    public Plant() 
    { 
        // 直接赋值父类的protected字段
        milk = false; 
        wings = false; 
        fruits = true; 
    } 

    public override string me() { return "Plants"; } 
} 

class Animelia : Kingdom 
{ 
    // 删除重复的私有字段
    public Animelia() 
    { 
        milk = true; 
        wings = true; 
        fruits = false; 
    } 

    public override string me() { return "Animals"; } 
} 

class Mamalia : Animelia 
{ 
    // 删除重复的私有字段
    public Mamalia() 
    { 
        // 覆盖Animelia设置的字段值
        wings = false; 
        fruits = false; 
    } 

    public override string me() { return "Mamals"; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
        Console.WriteLine("Hello World!\nLets learn Basic Kingdoms.\n"); 
        Kingdom p1 = new Plant(); 
        Kingdom m1 = new Mamalia(); 

        p1.Fly(); 
        p1.Milk(); 
        p1.Fruit(); 
        Console.WriteLine(); 
        m1.Fly(); 
        m1.Milk(); 
        m1.Fruit(); 
    } 
}

方式2:使用protected属性(更符合C#封装规范)

如果想贴合C#的封装实践,可以把父类的字段改成protected自动属性,既保留封装性,又让子类能修改属性值:

class Kingdom 
{ 
    protected bool Milk { get; set; }
    protected bool Wings { get; set; }
    protected bool Fruits { get; set; }

    public Kingdom() : this(true, true, true) {} 
    public Kingdom(bool milk, bool wings, bool fruits) 
    { 
        Milk = milk; 
        Wings = wings; 
        Fruits = fruits; 
    } 

    // 方法里改为访问属性
    public virtual void Fly() 
    { 
        if(Wings) { Console.WriteLine(me() + " may Fly."); } 
        else { Console.WriteLine(me() + " can not Fly."); } 
    } 

    // Fruit、Milk方法同理修改为访问对应属性
}

子类构造函数直接给这些属性赋值即可,同样删除子类的重复字段。

运行结果验证

现在运行代码,会得到预期输出:

Hello World!
Lets learn Basic Kingdoms.

Plants can not Fly.
Plants can not produce milk.
Plants may bear Fruits.

Mamals can not Fly.
Mamals may produce milk.
Mamals can not bear Fruits.

同时CS0414的警告会完全消失,因为子类不再有未被使用的字段,父类方法也能正确访问到子类设置的字段/属性值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:06:29