4

ゲーム用の非常に単純な在庫システムを設計しています。複数のタイプのオブジェクトを受け入れる必要があるインベントリ (特定のタイプの配列) があるという障害に遭遇しました。私のコード:

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 であるため、IWeapon または IArmour からではなく、IItem からのプロパティとメソッドのみが含まれます。したがって、サブクラス (サブインターフェース) IWeapon にある武器の名前にアクセスできないという問題が発生しました。スーパーインターフェイス (IItem) ではなく、サブインターフェイス (IWeapon または IArmour) でプロパティを探すようにリダイレクトする方法はありますか? 私は正しい道を進んでいますか?

4

9 に答える 9

11

最初のアイテムは常に武器であり、2 番目のアイテムは常に鎧であるため、配列 (または任意のデータ構造) を使用しないでください。1 つは武器を保持し、もう 1 つは鎧のインスタンスを保持する 2 つの別個のフィールドを用意するだけです。

private IWeapon weapon;
private IArmour armor;

public void initialiseInventory(IWeapon weapon, IArmour armour)
{
    this.weapon = weapon;
    this.armor = armor;
}
于 2013-02-08T17:48:39.807 に答える
1

親クラス/インターフェースでは、どの共通操作/属性が本当にここにあるのかを決定する必要があります。

次のようなインターフェースを持つ価値があるかもしれません:

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

}

その後、あなたはただ行くことができます

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

これは完璧ではなく、モデルについて疑問を投げかけますが、考えるべきことです。

于 2013-02-08T17:51:13.827 に答える
0

異なるインベントリ項目 (2 つの個別のフィールドだけでなく) を格納する配列が本当に必要であると仮定すると、継承を使用するだけでよいようです。使用例を明確にするために、自由に武器と防具にさまざまなプロパティを追加しました。

基本クラス:

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);
}
于 2013-02-08T18:20:05.157 に答える
0

私はServyが与えた答えに完全に同意しますが:

本当に配列 (または ?) を使用したい場合は、Name プロパティをインターフェイスList<IITem>に追加するだけです。IItem

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

長期的には役立つかどうかは疑問なので、Servyの回答に行きます.

于 2013-02-08T17:50:59.507 に答える
0

武器と防具の両方に名前があるため、それはIItemインターフェースに入れる必要があるプロパティです。

また、特定の位置には常に同じタイプのアイテムがあるため、異なる種類のアイテムの配列を持つことはあまり意味がありません。

それらに配列としてアクセスしたい場合は、配列を持ち、特定のタイプの装備されたアイテムにアクセスできるようにするクラスを作成できます。

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

}
于 2013-02-08T17:51:05.760 に答える
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;
    }
}

インベントリのクラスを設計する理由 TotalWeight や ItemCount プロパティなどを追加できるため、単に配列がある場合よりも簡単にIItem.

于 2013-02-08T18:12:55.267 に答える