I am trying to create a simple "inventory" of items, much like in any RPG. I have very basic classes made, which have properties.
Anyway, I have a base class of item
and inheriting from that is weapon
. item
has properties (name, value, weight, "important item") that are also used within weapon
, but weapon
has extra properties (attack, defense, speed, handedness).
I've got the following code (sorry if the readability is horrible):
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();
}
Basically, what I'm trying to do is add a new weapon
to the inventory, but the inventory is a List<item>
type. I went out on a whim hoping that, due to it's inheritance, it'd be accepted. It was, but the properties specific to weapon
aren't able to be accessed:
('shopSystem.item' does not contain a definition for 'Atk' and no extension method 'Atk' accepting a first argument of type 'shopSystem.item' could be found)
So, is there any way to achieve what I was intending here? Have an "inventory" which can store item
objects, as well as weapon
, armour
, accessory
etc. objects, which inherit from item
? It is also worth mentioning that I can access all of the desired properties if I declare the following:
weapon Foo = new weapon("Sword", 200, 20.00f, false, 30, 20, 1.10f, 1);
Many thanks for reading.
Here's the item
and weapon
classes, if anybody is interested:
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;}
}
}
In order to access the properties specific to the inherited class, you need to cast to the appropriate concrete class type. So, rather than accessing inventory[0]
, you need to access (weapon)inventory[0]
.
Also, if you are performing common tasks that will have different implementations based on the underlying class, such as logging the values to the console (which I realize was done for testing, but is a good example anyway), you should implement an overridable method in the base class.
For example, in the base class:
public virtual void LogProperties()
{
Console.Write("Name: {0}\nValue: {1}\nWeight: {2}\nDiscardable: {3}\nAttack",
this.Name, this.BValue, this.Weight, this.Discard);
}
And in the weapon class:
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);
}
Then, to access this:
inventory[0].LogProperties();
You are doing the right thing by using a List<item>
to store items and subclasses of items!
When you extract the item from the list, you just have to do a bit of work to test if it's a weapon
, or some other kind of item
.
To see if the element at position i
on the array is a weapon
, use the as
operator, which will return null
if the item is not the specified type (perhaps it is armour or some other type of item). This is known as a dynamic
cast. It works even if the item is null
.
weapon w = inventory[i] as weapon; // dynamic cast using 'as' operator
if (w != null)
{
// work with the weapon
}
Another way to do this is to check the type using the is
operator before doing a static
cast.
if (inventory[i] is weapon)
{
// static cast (won't fail 'cause we know type matches)
weapon w = (weapon)inventory[i];
// work with the weapon
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With