如何将多个对象添加到单个阵列?

时间:2013-02-08 17:46:41

标签: c# arrays object

我正在为游戏设计一个非常简单的库存系统。我遇到了一个障碍,我有一个需要接受多种类型对象的库存(一个特定类型的数组)。我的代码:

IWeapon[] inventory = new IWeapon[5];

public void initialiseInventory(IWeapon weapon, IArmour armour)
{
    inventory[0] = weapon; // Index 0 always contains the equipped weapon
    inventory[1] = armour; // Index 1 always contains the equipped armour
}

我会得到一个错误,指出数组无法将装甲对象转换为武器对象(这是数组类型)。然后我想我可以创建IWeapon和IArmour将继承的超类(嗯,界面准确)。但后来又遇到了另一个错误...

IItem[] inventory = new IItem[5];

public void initialiseInventory(IWeapon weapon, IArmour armour)
{
    inventory[0] = weapon; // Index 0 always contains the equipped weapon
    inventory[1] = armour; // Index 1 always contains the equipped armour

    Console.WriteLine("The weapon name is: " + inventory[0].Name) // Problem!
}

由于数组类型是IItem,它只包含来自IItem的属性和方法,而不包含来自IWeapon或IArmour的属性和方法。因此问题在于我无法访问位于子类(子接口)IWeapon中的武器的名称。有没有办法我可以以某种方式重定向它以寻找子接口(IWeapon或IArmour)中的属性而不是超级接口(IItem)?我甚至走在正确的道路上吗?

9 个答案:

答案 0 :(得分:11)

由于第一项总是是武器,第二项总是是盔甲,所以你根本不应该使用数组(或任何数据结构) 。只有两个单独的字段,一个持有武器,另一个持有装甲实例。

private IWeapon weapon;
private IArmour armor;

public void initialiseInventory(IWeapon weapon, IArmour armour)
{
    this.weapon = weapon;
    this.armor = armor;
}

答案 1 :(得分:2)

这是一个有趣(和常见)的谜题。你已经正确地弄清楚了它的第一部分:为了将元素存储在一个数组中,数组类型必须与进入数组的所有元素的共同祖先相匹配。当然,这将功能仅限于该共同祖先所提供的功能,这在您的情况下显然是不够的。

第二部分(即,一旦将所有元素都放在数组中,如何处理元素)会有点困难。您需要一个类型转换或多个分派。类型转换很简单:只需在元素前添加(IWeapon)

((IWeapon)inventory[0]).Name

对于多个项目,您可以使用LINQ:

foreach (IWeapon w in inventory.OfType<IWeapon>()) {
    Console.WriteLine("The weapon name is: " + w.Name);
}

多次发送要复杂得多。它允许您根据多个对象创建虚拟方法。作为回报,你必须牺牲语言提供的简单性:调用方法需要制作特殊对象,而不是直接调用方法。请查看Visitor Pattern以了解如何处理多个调度的一些想法。

答案 2 :(得分:2)

您可以使用is运算符来确定变量是否实现特定接口,然后将该变量强制转换为该接口的实例。

        if (inventory[0] is IWeapon)
        {
            IWeapon myWeapon = (IWeapon)inventory[0];
            Console.WriteLine("The weapon name is: " + myWeapon.Name);
        }

答案 3 :(得分:1)

在父类/接口中,您需要确定真正意义上的常用操作/属性。

可能值得拥有这样的界面:

Interface IItem  
{
    string name {get};
    string itemType {get};

}

然后你可以去

foreach(Iitem anItem in itemArray)
{
    Console.WriteLine("The " + anItem.itemType + " is: " + anItem.Name);
}

它并不完美,并且对您的模型提出了疑问,但它只是需要考虑的事情。

答案 4 :(得分:0)

虽然我完全赞同Servy给出的答案:

如果你真的想要使用数组(或List<IITem>?),你只需要将Name属性添加到IItem接口。

interface IItem
{
    string Name {get;set;}
}

我怀疑从长远来看它是否会对你有所帮助,所以我会选择Servy的答案。

答案 5 :(得分:0)

武器和装甲都有名字,所以这个属性应该放在IItem界面。

此外,Servy所说的是有道理的,因为特定的位置总是具有相同类型的项目,因此为不同类型的项目设置数组没有多大意义。

如果要将它们作为数组访问,可以创建一个两个都有数组的类,并允许您访问具有特定类型的配备项:

public class Inventory {

  public IWeapon CurrentWeapon { get; }
  public IArmour CurrentArmour { get; }

  private IItem[] _items = new IItem[8];

  public IItem[int idx] {
    get {
      return
        idx == 0 ? CurrentWeapon :
        idx == 1 ? CurrentArmour :
        idx_items[idx - 2];
    }
  }

}

答案 6 :(得分:0)

我发现接口和类之间有点混淆,但是,你应该非常简单地确保IItem上有Name属性(如果它是一个接口,IWeapon和IArmour需要实现),而不是放每个子类的Name属性(没有“子接口”:)) 也许你应该发布你的接口/类的代码....

答案 7 :(得分:0)

我必须加2美分,因为我发现这个问题很好,这可能是一个常见的问题。

我会选择这样的东西:

interface IItem
{
    //some common properties / methods
}

interface IWEapon : IItem
{
    string Name { get; set; } //maybe this should go to IItem? depends on your actual objects, of course
    //some other wepaon specific properties / methods
}

interface IArmor : IItem
{
    //some properties / methods
}

class Inventory
{
    public Inventory(IWEapon startWeapon, IArmor startArmor)
    {
        CurrentWeapon = startWeapon;
        CurrentArmor = startArmor;

        //optional:
        m_items.Add(startWeapon);
        m_items.Add(startArmor);
    }

    private List<IItem> m_items = new List<IItem>();
    IEnumerable<IItem> InventoryItems
    {
        get { return m_items; }
    }

    void AddItem(IItem item)
    {
        m_items.Add(item);
    }

    IWEapon CurrentWeapon
    {
        get;
        set;
    }

    IArmor CurrentArmor
    {
        get;
        set;
    }
}

为什么要为库存设计课程?因为你可以比只有IItem的数组更容易地添加像TotalWeight或ItemCount属性等的东西。

答案 8 :(得分:0)

假设您确实需要一个数组来存储不同的库存项目(而不仅仅是两个单独的字段),那么您似乎可以使用继承。我冒昧地为Weapon和Armor添加了不同的属性以澄清用例。

基类:

abstract class Item
{
    public string Name { get; set; }
}

派生类型:

class Weapon : Item
{
    public int Power { get; set; }
}

class Armor : Item
{
    public int Resistance { get; set; }
}

使用示例:

Item[] inventory = new Item[2];
inventory[0] = new Weapon { Name = "Singing Sword", Power = 10 };
inventory[1] = new Armor { Name = "Chainmail Shirt", Resistance = 5 };

// Note below that the Name property is always accessible because it is defined in the base class.

// Traverse only Weapon items
foreach (Weapon weapon in inventory.OfType<Weapon>())
{
    Console.WriteLine(weapon.Power);
}

// Traverse only Armor items
foreach (Armor armor in inventory.OfType<Armor>())
{
    Console.WriteLine(armor.Resistance);
}

// Travers all items
foreach (Item item in inventory)
{
    Console.WriteLine(item.Name);
}