不能强制转换作为派生类的继承类字段

本文关键字:继承 字段 派生 转换 不能 | 更新日期: 2023-09-27 18:22:28

在我解释我的问题之前,请记住,我选择了这样的架构,因为它将在 Unity 下的库存系统中使用,所以我不得不将 MonoBehavior 的Item与它的数据分开,这些数据只是用于库存目的的值......如果这是有道理的。

我有一个这样的架构:

public class ItemData
{
    // some fields...
    public string _name; //should be private with its properties but it doesn't matter in the current example
}
public class EquipmentData : ItemData
{
    // some additional fields...
    public float _weight;
}
public class Item
{
    private ItemData _data;
    //Properties
    public virtual ItemData Data { get; set; }
}
public class Equipment : Item
{
    //Properties
    public override ItemData Data 
    {
        get { return _data as EquipmentData; }
        set { _data = value as EquipmentData; }
    }
}

所以,基本上我有一个更深入的项目层次结构,但 1 个级别足以解释我自己。(它一直像武器:装备(...

问题是,如果我将private ItemData _data;留在Item类中,并在Equipment类中添加一个private EquipmentData _eData;,我将拥有两次ItemData字段,因为EquipmentData继承了其他派生类的ItemData依此类推......如果我有一个派生自Equipment等的类,第三次得到它......

像这样:

public class Item
{
    private ItemData _data;
}
public class Equipment : item
{
    private EquipmentData _eData;
}

ItemData的字段(例如_name(将在Equipment中出现两次,我不希望这样......

所以我猜我的架构有问题,可能有一种方法可以绕过这种方法,看起来有点"脏",但我在网上找不到任何针对这个问题的具体内容,我已经达到了我的极限。

我尝试过的:

  • 我尝试使用关键字 new Equipment认为我可以隐藏初始protected ItemData _data; that is in my Item类,然后在Equipmentprotected new EquipmentData _data;,但它显然不允许我,因为 Shadow _data它需要是相同的类型,似乎不适用于派生类型。
  • 此外,如我的代码示例所示,我尝试重写该属性以根据调用它的类返回正确的类型,强制转换始终返回null...

仍然觉得很奇怪,我最终试图实现这样的东西,所以我对新的想法持开放态度,以更好的方式重组事物,或者如果有人有一个我没有想到的解决方案来保持这种方式,但让它们工作,那就太好了。

我希望我的问题足够详细,如果没有,如果需要,我可以澄清事情。

不能强制转换作为派生类的继承类字段

你需要的是泛型类。通过这种方式,您可以为每个Item分配其正确的ItemData类型。因此,Equipment将分配其EquipmentData

//TItemData is a name of this generic type. 
//It could be T for example, just like variable name. 
//These type names start from T by convention. 
//This is not a new class or something like that.
//where TItemData : ItemData is a constraint, 
//that assumes that this type should be a subtype of ItemData
public abstract class Item<TItemData> where TItemData : ItemData
{
    protected TItemData Data;
}
//EquipmentData is a subtype of ItemData, so it fits here. 
//No chances to write, for example, IntEquipment : Item<int> , 
//because int does not derive from ItemData.
public class Equipment : Item<EquipmentData>
{
    //here Data will be of EquipmentData type, without any casting.
}

通过实现上述内容,您将实现类型安全。

编辑

要做一个适当扩展Equipment的类(我们称之为Weapon(,并有其适当的ItemData(我们称之为WeaponData(,你需要写这样的东西:

编辑Equipment,并使其abstract

public abstract class Equipment<TEquipmentData> 
: Item<TEquipmentData> 
//this constraint is VERY important, as EquipmentData derives from ItemData, thus fulfill Item<TItemData> constraint.
where TEquipmentData : EquipmentData
{
    //Data will have EquipmentData type here.
}

创建WeaponData

public WeaponData : EquipmentData
{
}

创建Weapon

public class Weapon : Equipment<WeaponData>
{
   //Data will have WeaponData type here.
}

这有效:

public class OverridePropertiesWithSameField
{
    public void Test()
    {
        ChildItem ci = new ChildItem();
        ChildItemData cid = new ChildItemData();
        cid.ItemDataProp = "ItemDataProperty"; // Inherited
        cid.ChildItemDataProp = "ChildItemDataProp"; // Specific
        ci.ItemData = cid;
        // You know you need ChildItemData type here.
        var childItemData = ci.ItemData as ChildItemData;
        string itemDataProp = childItemData.ItemDataProp;
        string childItemDataProp = childItemData.ChildItemDataProp;
    }
}
public class Item
{
    protected ItemData data;
    public virtual ItemData ItemData { get; set; }
}
public class ChildItem : Item
{
    public override ItemData ItemData
    {
        get { return base.data; }
        set { base.data = value; }
    }
}
public class ItemData
{
    public string ItemDataProp { get; set; }
}
public class ChildItemData : ItemData
{
    public string ChildItemDataProp { get; set; }
}

可以使用泛型类型参数和泛型类型约束(where(。

public class Item<DATA> where DATA : ItemData
{
    public virtual DATA Data { get; set; }
}

现在,您的类可以使用特定的 ItemData:

Item<ItemData> has property 
public virtual ItemData Data { get; set; }
Item<EquipmentData> has property
public virtual EquipmentData Data { get; set; }
Item<ANOTHER> has property
public virtual ANOTHER Data { get; set; }