无法转换继承的 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" 的方法,但我在网上找不到任何针对这个问题的具体信息,我已经达到我的极限了。
我尝试过的:
- 我曾尝试在
Equipment
中使用关键字 new
,认为我可以隐藏 Item
class 中的初始 protected ItemData _data;
,然后在 Equipment
中有 protected new EquipmentData _data;
但它显然不允许我使用 Shadow _data 它需要相同的类型,似乎不适用于派生类型。
- 此外,如我的代码示例所示,我已尝试将 属性 覆盖为 return 正确的类型,具体取决于调用的 class ,强制转换总是 return
null
...
我仍然觉得很奇怪,我最终尝试实现类似的东西,所以我愿意接受新的想法,以更好的方式重组事物,或者如果有人有我没有想过的解决方案这样的事情,但让他们工作,那就太好了。
我希望我的问题足够详细,如果没有,我可以在需要时解决问题。
你需要的是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; }
在我解释我的问题之前,请记住我选择了这样的架构,因为它将在 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" 的方法,但我在网上找不到任何针对这个问题的具体信息,我已经达到我的极限了。
我尝试过的:
- 我曾尝试在
Equipment
中使用关键字new
,认为我可以隐藏Item
class 中的初始protected ItemData _data;
,然后在Equipment
中有protected new EquipmentData _data;
但它显然不允许我使用 Shadow _data 它需要相同的类型,似乎不适用于派生类型。 - 此外,如我的代码示例所示,我已尝试将 属性 覆盖为 return 正确的类型,具体取决于调用的 class ,强制转换总是 return
null
...
我仍然觉得很奇怪,我最终尝试实现类似的东西,所以我愿意接受新的想法,以更好的方式重组事物,或者如果有人有我没有想过的解决方案这样的事情,但让他们工作,那就太好了。
我希望我的问题足够详细,如果没有,我可以在需要时解决问题。
你需要的是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; }