不能强制转换作为派生类的继承类字段
本文关键字:继承 字段 派生 转换 不能 | 更新日期: 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 myItem
类,然后在Equipment
中protected 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; }