我正在尝试创建一个简单的“库存”项目,就像在任何RPG中一样。我有非常基本的类,它们都有属性。
无论如何,我有一个基类item
,并继承自weapon
。 item
具有在weapon
内使用的属性(名称,值,权重,“重要项目”),但weapon
具有额外属性(攻击,防御,速度,手性)。< / p>
我有以下代码(对不起,如果可读性太可怕了):
static void Main(string[] args)
{
List<item> inventory = new List<item>();
inventory.Add(new weapon("Souleater", 4000, 25.50f, false, 75, 30, 1.25f, 2));
//item---------------------------> weapon--------->
Console.Write("Name: {0}\nValue: {1}\nWeight: {2}\nDiscardable: {3}\nAttack: {4}\nDefense: {5}\nSpeed: {6}\nHandedness: {7}",
inventory[0].Name, inventory[0].BValue, inventory[0].Weight, inventory[0].Discard,
inventory[0].Atk, inventory[0].Def, inventory[0].Speed, inventory[0].Hands);
Console.ReadLine();
}
基本上,我要做的是向广告资源添加新的weapon
,但广告资源是List<item>
类型。我一时兴起,希望由于它的继承,它会被接受。它是,但无法访问特定于weapon
的属性:
('shopSystem.item'不包含'Atk'的定义,也没有扩展方法'Atk'可以找到'shopSystem.item'类型的第一个参数
那么,有什么方法可以达到我的目的吗?有一个“广告资源”可以存储item
个对象,以及从weapon
继承的armour
,accessory
,item
等对象?还值得一提的是,如果我声明以下内容,我可以访问所有需要的属性:
weapon Foo = new weapon("Sword", 200, 20.00f, false, 30, 20, 1.10f, 1);
非常感谢您阅读。
以下是item
和weapon
类,如果有人感兴趣的话:
class item
{
#region Region: Item Attributes
protected string name = "";
protected int baseValue = 0;
protected float weight = 0.00f;
protected bool noDiscard = false;
#endregion
public item(string n, int v, float w, bool nd){
name = n; baseValue = v; weight = w; noDiscard = nd;}
public string Name{
get{return name;}
set{if(value != ""){
name = value;}
}//end set
}
public int BValue{
get{return baseValue;}
}
public float Weight{
get{return weight;}
}
public bool Discard{
get{return noDiscard;}
}
}
class weapon : item
{
#region Region: Weapon Attributes
private int atk = 0;
private int def = 0;
private float speed = 0.00f;
private byte hands = 0;
#endregion
public weapon(string n, int v, float w, bool nd, int a, int d, float s, byte h) : base(n, v, w, nd){
atk = a; def =d; speed = s; hands = h;}
public int Atk{
get{return atk;}
}
public int Def{
get{return def;}
}
public float Speed{
get{return speed;}
}
public byte Hands{
get{return hands;}
}
}
答案 0 :(得分:8)
要访问特定于继承类的属性,需要转换为适当的具体类类型。因此,您需要访问inventory[0]
。
(weapon)inventory[0]
此外,如果您执行的常见任务将基于底层类具有不同的实现,例如将值记录到控制台(我意识到已经完成了测试,但无论如何都是一个很好的示例),您应该实现基类中的可覆盖方法。
例如,在基类中:
public virtual void LogProperties()
{
Console.Write("Name: {0}\nValue: {1}\nWeight: {2}\nDiscardable: {3}\nAttack",
this.Name, this.BValue, this.Weight, this.Discard);
}
在武器类中:
public override void LogProperties()
{
Console.Write("Name: {0}\nValue: {1}\nWeight: {2}\nDiscardable: {3}\nAttack: {4}\nDefense: {5}\nSpeed: {6}\nHandedness: {7}",
this.Name, this.BValue, this.Weight, this.Discard,
this.Atk, this.Def, this.Speed, this.Hands);
}
然后,要访问它:
inventory[0].LogProperties();
答案 1 :(得分:2)
使用List<item>
来存储项目的子项和子类,这样做是正确的!
从列表中提取项目时,您只需要做一些工作来测试它是weapon
还是其他类型的item
。
要查看数组上i
位置的元素是否为weapon
,请使用as
运算符,如果该项不是指定的话,它将返回null
类型(也许是盔甲或其他类型的物品)。这被称为dynamic
演员。即使项目为null
,它也能正常工作。
weapon w = inventory[i] as weapon; // dynamic cast using 'as' operator
if (w != null)
{
// work with the weapon
}
另一种方法是在执行is
演员之前使用static
运算符检查类型。
if (inventory[i] is weapon)
{
// static cast (won't fail 'cause we know type matches)
weapon w = (weapon)inventory[i];
// work with the weapon
}
答案 2 :(得分:1)
这是Linq在处理多态时可以成为你的朋友的地方。铸造物品的问题是当给定的索引不是正确的类型时。 (即inventory[0]
不是weapon
,(weapon)inventory[0]
将投掷。)
您可以使用以下方法来避免异常:
var myWeapon = inventory[0] as weapon;
然而,你将在任何地方进行#null检查。使用Linq可以获得很大的灵活性:
var weapons = inventory.OfType<weapon>();
从这里,您可以使用Where
,FirstOrDefault
等来查找您感兴趣的数据或迭代武器。
答案 3 :(得分:0)
您可以实现一个公共接口(例如IItem
),通过该接口查询项的属性,或者实现一个公共基类,可能是一个抽象基类,并将其用作类型T
List
的。{
如果使用后一个选项,请确保在适当的情况下覆盖基类的函数,多态性将完成其余的工作。
答案 4 :(得分:0)
您需要将值转换回weapon
才能访问这些属性,即((weapon)inventory[0]).Atk)
。请注意括号:强制转换的优先级低于字段访问权限,因此您无法编写(weapon)inventory[0].Atk
;这将被解释为(weapon)(inventory[0].Atk)
。
您还需要区分不同的类(例如,您可能还有一个armor
类)。最简单的方法是在基类item
上添加一个额外的值,告诉你对象的实际类型,然后进行相应的转换。
然而,更好的方法是使用继承 - 让item
定义一系列可以处理所有通用内容的方法 - 例如显示有关该项的信息 - 然后在继承类中覆盖它。也就是说,不是直接访问所有数据,而是调用一种以合理的方式组合它的方法。对于您的特定示例,您将项目转换为字符串,因此覆盖ToString()可能是有意义的 - 这意味着您可以执行此操作:
Console.Write(inventory[0]);
并且取决于它是项目还是武器,相应类的ToString()将被调用(通常,您必须调用方法本身,但ToString()是特殊的,因为所有对象都具有方法,所以Console.Write为你做了。)
在你的武器类中,你可以像这样实现ToString方法:
public string ToString() {
//Put all of the data in here, like in your example
return String.Format("Name: {0}\n...", name, ...);
}