无法转换继承的 class 字段,它是派生的 class

Can't cast inherited class field which is a derived class

在我解释我的问题之前,请记住我选择了这样的架构,因为它将在 Unity 下的库存系统中使用,所以我必须将 Item 分开MonoBehavior 只是来自其数据的世界中的某些东西,这些数据只是用于库存目的的值...如果这有意义的话。

我的架构是这样的:

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 层足以解释我自己。 (它一直像武器:装备)...

问题是,如果我在 Item class 中保留 private ItemData _data;,并在 Equipment class 中添加一个 private EquipmentData _eData;,我将有两次 ItemData 字段,因为 EquipmentData 继承 ItemData 等其他派生的 classes...如果我有一个 [=60] 第三次得到它=] 派生自 Equipment 等等...

类似于:

public class Item
{
    private ItemData _data;
}

public class Equipment : item
{
    private EquipmentData _eData;
}

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

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

我尝试过的:

我仍然觉得很奇怪,我最终尝试实现类似的东西,所以我愿意接受新的想法,以更好的方式重组事物,或者如果有人有我没有想过的解决方案这样的事情,但让他们工作,那就太好了。

我希望我的问题足够详细,如果没有,我可以在需要时解决问题。

你需要的是Generic Classes。这样,您可以为每个 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.
}

通过实施上述你将实现Type Safety

编辑

制作一个 class 适当地扩展 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; }
}

现在您的 class 可以使用特定的 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; }