C#List <baseclass> - 用于存储继承类的任何方法吗?</baseclass>

时间:2012-07-15 22:44:57

标签: c# list inheritance

我正在尝试创建一个简单的“库存”项目,就像在任何RPG中一样。我有非常基本的类,它们都有属性。

无论如何,我有一个基类item,并继承自weaponitem具有在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继承的armouraccessoryitem等对象?还值得一提的是,如果我声明以下内容,我可以访问所有需要的属性:

weapon Foo = new weapon("Sword", 200, 20.00f, false, 30, 20, 1.10f, 1);

非常感谢您阅读。

以下是itemweapon类,如果有人感兴趣的话:

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

}

5 个答案:

答案 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>();

从这里,您可以使用WhereFirstOrDefault等来查找您感兴趣的数据或迭代武器。

答案 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, ...);
}