无法转换继承的类字段,这是一个派生类

时间:2015-11-19 09:17:23

标签: c# inheritance unity3d architecture override

在我解释我的问题之前,请记住我选择了这样的架构,因为这将在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级足以解释自己。 (它继续像武器:装备一样)......

问题是,如果我将private ItemData _data;留在Item课程中,并在private EquipmentData _eData;课程中添加Equipment,我会有ItemData个字段两次因为EquipmentData继承了其他派生类的ItemData等等...如果我有一个派生自Equipment等的类,那么第三次获取它......

类似的东西:

public class Item
{
    private ItemData _data;
}

public class Equipment : item
{
    private EquipmentData _eData;
}

ItemData的{​​{1}}字段会在_name中出现两次,我不希望这样......

所以我猜我的架构有问题,而且这种方法可能有一种看起来很脏的方法,但是我找不到任何针对这个问题的方法。在线,我已达到极限。

我尝试过:

  • 我尝试在Equipment中使用关键字new,以为我可以隐藏Equipment课程中的初始protected ItemData _data;,然后Itemprotected new EquipmentData _data;,但它显然不允许我因为Shadow _data它需要是相同的类型,似乎不适用于派生类型。
  • 另外,如我的代码示例所示,我已尝试覆盖属性以根据调用的类返回正确的类型,强制转换始终返回Equipment ...

我仍然觉得很奇怪,我最终试图实现类似的东西,所以我愿意接受新的想法,以更好的方式重组事物,或者如果有人有解决方案,我还没想到要保持这样的事情,但让它们工作,它会非常好。

我希望我的问题足够详细,如果不是,我可以在必要时清理。

3 个答案:

答案 0 :(得分:0)

您需要的是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

修改

要创建一个正确扩展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.
}

答案 1 :(得分:0)

这有效:

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; }
}

答案 2 :(得分:0)

您可以使用泛型类型参数,使用泛型类型约束(where)。

routes

现在你的班级可以使用特定的ItemData:

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