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

如何正确创建并行继承层级?C#动物类与颜色数据类场景示例

问题描述

我有一个基于C#和MonoBehaviour的动物继承层级,原始代码如下:

abstract class Animal : MonoBehaviour
{
    public int Health;

    public Color MainColor;

    public virtual bool HasColor(Color color)
    {
        return MainColor == color;
    }
}
    
abstract class CarnivorousAnimal : Animal
{
    public int Damage;

    public List<Color> SecondaryColors;

    public override bool HasColor(Color color)
    {
        return base.HasColor(color) || SecondaryColors.Contains(color);
    }
}
    
class Cat : CarnivorousAnimal
{
    public float MeowLoudness;

    public Color FurColor;

    public override bool HasColor(Color color)
    {
        return base.HasColor(color) || FurColor == color;
    }
}

为了遵循单一职责原则(SRP),我打算把所有与颜色相关的数据和方法迁移到独立的并行层级(AnimalColorData、CarnivorousAnimalColorData、CatColorData),通过ColorData字段关联。颜色数据类代码如下:

class AnimalColorData
{
    public Color MainColor;

    public virtual bool HasColor(Color color)
    {
        return MainColor == color;
    }
}

class CarnivorousAnimalColorData : AnimalColorData
{
    public List<Color> SecondaryColors;

    public override bool HasColor(Color color)
    {
        return base.HasColor(color) || SecondaryColors.Contains(color);
    }
}

class CatColorData : CarnivorousAnimalColorData
{
    public Color FurColor;

    public override bool HasColor(Color color)
    {
        return base.HasColor(color) || FurColor == color;
    }
}

我最初尝试修改动物层级为如下结构,但这段代码存在问题:Cat类会拥有3份ColorData字段,属于隐藏基类成员的错误实现,无法正常工作:

abstract class Animal : MonoBehaviour
{
    public int Health;
    public AnimalColorData ColorData;
}

abstract class CarnivorousAnimal : Animal
{
    public int Damage;
    public CarnivorousAnimalColorData ColorData;
}

class Cat : CarnivorousAnimal
{
    public float MeowLoudness;
    public CatColorData ColorData;
}

我期望实现的效果是:同一个Cat实例的ColorData在不同类型的引用下,能正确访问对应层级的颜色数据和方法,示例代码如下:

Cat cat = new Cat();
cat.ColorData.MainColor = Color.green;
cat.ColorData.FurColor = Color.cyan;

CarnivorousAnimal animal = cat;
Console.WriteLine(animal.ColorData.HasColor(Color.cyan)); // 期望输出false
Console.WriteLine(cat.ColorData.HasColor(Color.cyan)); // 期望输出true

另外,我认为泛型不是最优解,因为每次使用基类时都必须指定类型。请问该如何正确实现?


解决方案

方法1:基类用受保护字段+子类强类型属性(推荐)

将基类的ColorData设为受保护字段存储实例,子类通过公共属性返回该字段的强转版本,这样所有层级共享同一个ColorData实例,不会产生重复:

abstract class Animal : MonoBehaviour
{
    public int Health;
    // 受保护字段,存储实际的ColorData实例
    protected AnimalColorData _colorData;

    // 对外暴露基类类型的ColorData属性
    public AnimalColorData ColorData => _colorData;

    // 构造函数初始化,确保子类可以传入对应类型的实例
    protected Animal(AnimalColorData colorData)
    {
        _colorData = colorData;
    }
}

abstract class CarnivorousAnimal : Animal
{
    public int Damage;

    // 子类的强类型属性,返回转换后的ColorData
    public new CarnivorousAnimalColorData ColorData => (CarnivorousAnimalColorData)_colorData;

    protected CarnivorousAnimal(CarnivorousAnimalColorData colorData) : base(colorData)
    {
    }
}

class Cat : CarnivorousAnimal
{
    public float MeowLoudness;

    // Cat层级的强类型属性
    public new CatColorData ColorData => (CatColorData)_colorData;

    // 构造函数传入CatColorData实例,确保类型匹配
    public Cat() : base(new CatColorData())
    {
    }
}

使用时完全符合预期效果:

Cat cat = new Cat();
cat.ColorData.MainColor = Color.green;
cat.ColorData.FurColor = Color.cyan;

CarnivorousAnimal animal = cat;
Console.WriteLine(animal.ColorData.HasColor(Color.cyan)); // 输出false(调用AnimalColorData的HasColor)
Console.WriteLine(cat.ColorData.HasColor(Color.cyan)); // 输出true(调用CatColorData的HasColor)

方法2:显式接口实现

如果希望彻底避免字段隐藏的警告,可以定义泛型接口,让每个层级显式实现对应类型的接口:

// 定义泛型接口,用于获取特定类型的ColorData
public interface IHasColorData<T> where T : AnimalColorData
{
    T ColorData { get; }
}

abstract class Animal : MonoBehaviour, IHasColorData<AnimalColorData>
{
    public int Health;
    protected AnimalColorData _colorData;

    // 显式实现接口
    AnimalColorData IHasColorData<AnimalColorData>.ColorData => _colorData;

    // 对外的非泛型属性,方便直接访问基类ColorData
    public AnimalColorData ColorData => _colorData;

    protected Animal(AnimalColorData colorData)
    {
        _colorData = colorData;
    }
}

abstract class CarnivorousAnimal : Animal, IHasColorData<CarnivorousAnimalColorData>
{
    public int Damage;

    // 显式实现接口
    CarnivorousAnimalColorData IHasColorData<CarnivorousAnimalColorData>.ColorData => (CarnivorousAnimalColorData)_colorData;

    // 子类的强类型属性
    public new CarnivorousAnimalColorData ColorData => (CarnivorousAnimalColorData)_colorData;

    protected CarnivorousAnimal(CarnivorousAnimalColorData colorData) : base(colorData)
    {
    }
}

class Cat : CarnivorousAnimal, IHasColorData<CatColorData>
{
    public float MeowLoudness;

    // 显式实现接口
    CatColorData IHasColorData<CatColorData>.ColorData => (CatColorData)_colorData;

    // Cat层级的强类型属性
    public new CatColorData ColorData => (CatColorData)_colorData;

    public Cat() : base(new CatColorData())
    {
    }
}

这种方式既可以通过接口获取特定类型的ColorData,也能保持层级结构的清晰性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:54:56