8

他のRPGと同じように、アイテムの単純な「インベントリ」を作成しようとしています. プロパティを持つ非常に基本的なクラスを作成しました。

とにかく、私は の基本クラスを持っており、itemそれを継承していweaponます。には、 内でitemも使用されるプロパティ (名前、値、重量、「重要なアイテム」) がありますが、追加のプロパティ (攻撃、防御、速度、利き手) があります。weaponweapon

私は次のコードを持っています(読みやすさがひどい場合は申し訳ありません):

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」の定義が含まれておらず、タイプ「shopSystem.item」の最初の引数を受け入れる拡張メソッド「Atk」が見つかりませんでした)

それで、私がここで意図していたことを達成する方法はありますか? から継承した、などのオブジェクトitemだけでなく、オブジェクトを格納できる「インベントリ」があります。次のように宣言すると、必要なすべてのプロパティにアクセスできることにも言及する価値があります。weaponarmouraccessoryitem

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

読んでくれてありがとう。

誰かが興味を持っているなら、ここにitemandクラスがあります: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;}
    }

}
4

5 に答える 5

7

継承されたクラスに固有のプロパティにアクセスするには、適切な具象クラス タイプにキャストする必要があります。したがって、 にアクセスするのではなく、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();
于 2012-07-15T22:53:55.250 に答える
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
} 
于 2012-07-16T00:14:57.203 に答える
1

これは、ポリモーフィズムを扱うときに Linq が役立つ場所です。項目をキャストする際の問題は、指定されたインデックスが正しい型でない場合です。(つまり、 ではinventory[0]なく、weaponスロー(weapon)inventory[0]されます。)

以下を使用して例外を回避できます。

var myWeapon = inventory[0] as weapon;

ただし、どこでも #null チェックを行うことになります。Linq を使用すると、多くの柔軟性が得られます。

var weapons = inventory.OfType<weapon>();

ここから 、 などを使用してWhereFirstOrDefault興味のあるデータを見つけたり、武器を反復したりできます。

于 2012-07-16T02:00:15.143 に答える
0

IItemアイテムのプロパティをクエリするための共通のインターフェイス(例)を実装するか、共通の基本クラス(おそらく抽象クラス)を実装して、それをのタイプTとして使用できますList。後者のオプションを使用する場合は、必要に応じて基本クラスの関数をオーバーライドしてください。残りはポリモーフィズムが行います。

于 2012-07-15T22:57:09.170 に答える
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, ...);
}
于 2012-07-15T22:58:00.747 に答える