2012-07-15 1 views
5

私はアイテムの簡単な「在庫」を作成しようとしています。これはどんなRPGにもよく似ています。私は非常に基本的なのクラスを持っている、プロパティを持っています。C#List <baseClass> - 継承されたクラスを格納する方法もありますか?

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

(可読性が恐ろしいの場合は申し訳ありません)私は、次のコードを持っている:

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を追加しているが、在庫はAですList<item>タイプ。私はそれが継承のために受け入れられることを望んで、気まぐれに出かけました。それはあったが、weaponに固有のプロパティにアクセスすることができない。

( 'shopSystem.itemが「攻撃力」タイプの最初の引数を受け入れる「攻撃力」の定義とのない拡張メソッドが含まれていません'shopSystem.item'が見つかりました)

ここで私がここで意図していたことを達成する方法はありますか? itemオブジェクトを格納できる "目録"と、を継承するweaponarmouraccessoryなどのオブジェクトがありますか?私が次のことを宣言した場合、私は、所望の特性のすべてにアクセスできることも言及する価値がある:読書のための

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

感謝します。誰もが興味を持っている場合はここ

は、itemweaponクラスです:

​​

答えて

8

継承されたクラスに固有のプロパティにアクセスするためには、適切な具体的なクラス型にキャストする必要があります。したがって、inventory[0]にアクセスするのではなく、(weapon)inventory[0]にアクセスする必要があります。

また、コンソールに値を記録するなど、基本的なクラスに基づいて実装が異なる一般的なタスクを実行している場合(テスト用に実現されたとは思いますが、とにかく良い例です)、基本クラスにオーバーライド可能なメソッドを実装します。これにアクセスするには、次に

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

、::

public virtual void LogProperties() 
{ 
Console.Write("Name: {0}\nValue: {1}\nWeight: {2}\nDiscardable: {3}\nAttack", 
      this.Name, this.BValue, this.Weight, this.Discard); 
} 

武器クラスのベースクラスで例えば

inventory[0].LogProperties(); 
+1

私は '(weapon)inventory [0] .Atk'を使っても、同じエラーメッセージが表示されます。 – Deadrust

+1

((武器)の目録[0])を使用してみてください。代わりに –

+0

アーク、それが動作します!ありがとう! – Deadrust

0

あなたは、共通のを実装することができますインターフェイス(例:IItem)を使用してアイテムのプロパティを照会するか、共通の基本クラスproそれは抽象的なものであり、のタイプTとして使用します。 後者のオプションを使用する場合は、必要に応じて基本クラスの関数をオーバーライドして、残りの部分を多態性で処理してください。

0

((weapon)inventory[0]).Atk)などのプロパティにアクセスするには、値をweaponにキャストする必要があります。かっこに注意してください。キャストはフィールドアクセスよりも優先度が低いため、(weapon)inventory[0].Atkと書くことはできません。それは(weapon)(inventory[0].Atk)と解釈されます。

また、異なるクラスを区別する必要があります(たとえば、おそらくarmorクラスもあります)。これを行う最も簡単な方法は、基本クラスitemに余分な値を追加して、オブジェクトの実際のタイプを通知し、それに応じてキャストすることです。

しかし、より良いアプローチは、継承を使用することです。itemは、すべての一般的なものを処理できる一連のメソッドを定義します。項目に関する情報を表示し、継承クラスでオーバーライドします。つまり、そのデータのすべてに直接アクセスするのではなく、それを合理的な方法で組み合わせるメソッドを呼び出します。 - あなたの特定の例について、あなたは文字列に項目を変換しているので、それはおそらく、toString()をオーバーライドするために理にかなって、それはあなたがこれを行うことができるだろう意味:

Console.Write(inventory[0]); 

、それがあるかどうかに応じて、アイテムや武器の場合、適切なクラスのToString()が呼び出されます(通常、メソッド自体を呼び出す必要がありますが、ToString()はすべてのオブジェクトにそのメソッドがあるため特殊です。君は)。あなたの武器クラスで

、あなたは、このようにToStringメソッドを実装したい:

public string ToString() { 
    //Put all of the data in here, like in your example 
    return String.Format("Name: {0}\n...", name, ...); 
} 
+0

私はそのToStringメソッドが好きです。ただし、数式で使用するプロパティ(たとえば、.Atkプロパティ)のうちの1つにアクセスする場合はどうすればよいですか?つまり、(武器の在庫[0])のように保つのが最善でしょうか?私が作成していた文字列は、値が正しく格納されていることをテストすることでした。 – Deadrust

+0

@Deadrust:そうすることができますし、 'weapon usedWeapon =(weapon)inventory [0];'を実行して、usedWeaponのすべてのプロパティに追加のキャスティングをせずにアクセスすることもできます。あなたはおそらくそれを以前よりもやりたいと思っています。現在装備されている武器を 'player'クラスや' unit'クラスに格納しますが、RPGはこれに対するアプローチが異なります。 –

+0

また、この例ではToStringを使用する必要はありません。独自のメソッドを定義し、それを呼び出すことは、あなたのクラスで何をするつもりかによって決まります。 –

2

あなたはアイテムのアイテムとサブクラスを格納するList<item>を使用して正しいことをやっています!

リストから項目を抽出するときは、それがweaponであるか、またはitemであるかどうかをテストするための少しの作業が必要です。

アレイ上の位置iの要素がweaponある場合アイテムが指定されたタイプ(おそらくそれが装甲またはアイテムのいくつかの他のタイプである)でない場合nullが返されas演算子を使用し、参照します。これはキャストdynamicとして知られています。アイテムがnullであっても機能します。

weapon w = inventory[i] as weapon; // dynamic cast using 'as' operator 
if (w != null) 
{ 
    // work with the weapon 
} 

これを行うための別の方法はstaticキャストを行う前にis演算子を使用してタイプをチェックすることです。

if (inventory[i] is weapon) 
{ 
    // static cast (won't fail 'cause we know type matches) 
    weapon w = (weapon)inventory[i];   

    // work with the weapon 
} 
+1

2番目のテストの代わりに、 'if(inventory [i]がweaponである)'。しかし、オブジェクトを2回キャスティングすることを避けるため、最初の例( 'as '付き)はおそらく好ましいでしょう。 :) –

+0

@DanJうん、ありがとう!これはまた、ヌルチェックの必要性を取り除く。それに応じて回答を調整します。 :) –

+0

最初の例は、 'inventory'インスタンスにアイテムを動的に追加し始めたときに、すぐに必要なものです。どうもありがとう! – Deadrust

1

これは多型を扱う際にLinqがあなたの友人になる場所です。アイテムのキャストに関する問題は、指定されたインデックスが正しいタイプでない場合です。 (すなわちinventory[0]weaponない、(weapon)inventory[0]がスローされます。)

あなたが使用して例外を回避することができます

var myWeapon = inventory[0] as weapon; 

をしかし、あなたはどこにでも#NULLチェックをやってます。あなたが興味を持っているか、武器を反復処理するデータを見つけることWhereFirstOrDefaultなどを使用することができますここから

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

:LINQのを使用して、あなたは多くの柔軟性を得ます。

+0

+1これは私のアプローチであり、コードのどれだけが一般的な在庫を認識しなければならないかを制限します。例えば、 'List 'に作用し、 'inventory.OfType ()'を渡すメソッドを書くことができます。この方法では、在庫に他の種類の品目が存在することを心配する必要はありません。 –

関連する問題