2016-07-17 4 views
1

私は、いくつかの一般的なフィールド(例:名前、健康)を保存する抽象クラスAnimalを持っています。私は多くの動物クラス、例えばタイガーを持っていますが、他の動物クラスには追加フィールドがあるクラスFishもあります。canSplash抽象クラスオブジェクトのリストから子クラスのプロパティにアクセスする

私はAnimalオブジェクトのリストを持っています。共通のフィールドにはアクセスできますが、FishのフィールドcanSplashにはアクセスできません。私は抽象クラスから具体的なクラスの特定のフィールドにアクセスするための助けを探しています。

class Zoo 
{ 
    public List<Animal> animals = new List<Animal>(); 

    public Zoo() 
    { 
     animals.Add(new Monkey()); 
     animals.Add(new Tiger()); 
     animals.Add(new Fish()); 
    } 

    public static void displayZooPopulation() 
    { 
     foreach (var a in animals) 
     { 
      if (a.species == "fish" && a.CanSplash) 
      { 
       Console.WriteLine("{0} can splash",a.Name); 
      } 
     } 
    } 
} 

class Fish : Animal { 
    private bool canSplash 
    public bool CanSplash { get; set; } 
} 
+0

なぜCanSplashは浮動小数点ですか?なぜcanSplashはプライベートですか? – jdweng

+0

canSplashは、getsとsetsを使ってアクセスするため、privateです。申し訳ありませんが、フロートはこの質問を入力した間違いでした。 – ecclesm

+2

フィールドを削除する:private bool canSplash、あなたはそれをする必要はありません。 –

答えて

3

簡単な答えは安全ににキャストで型をチェックし、それがnullないかどうかを確認、次のようになります。

var fish = a as Fish; 
if (fish != null && fish.CanSplash) 
{ 
    Console.WriteLine("{0} can splash",a.Name); 
} 

だけ、この特定を持っている一人の子供のクラスを持っている場合、これは完全に大丈夫です動作。 しかし、象が言うように、スプラッシュすることができる動物の他の子供クラスもあると考えてください。あなたの動物園のすべての動物が飛び散らないようにするには、ゾウのクラスもチェックしなければなりません。

より良いアプローチはISplashableのようなもののためのインターフェースを使用することです:

public interface ISplashable 
{ 
    bool CanSplash { get; } 
} 

今飛散することができるはずですあなたの子供のクラスのすべてにこのインタフェースを実装:今すぐ

public class Fish : Animal, ISplashable 
{ 
    // ... 

    public bool CanSplash { get; set; } // this also implements CanSplash { get; } 

    // ... 
} 

public class Elephant : Animal, ISplashable 
{ 
    // ... 

    public bool CanSplash { get { return true; } } 

    // ... 
} 

具体的なクラスの代わりにそのインタフェースに対してチェックすることができます:

var splasher = a as ISplashable; 
if (splasher != null && splasher.CanSplash) 
{ 
    Console.WriteLine("{0} can splash",a.Name); 
} 
+0

ありがとう、完璧に働いた。 – ecclesm

+0

インタフェースを使った拡張された答えに感謝します。この場合は本当に役立つばかりでなく、インターフェイスを使用することも私にははっきりと分かりました。どうもありがとうございました! – ecclesm

0
public void displayZooPopulation() 
    { 
     foreach (var a in animals) 
     { 
      if (a is Fish) 
      { 
//here sure "a" is not null, no need to check against null 
       var fish = a as Fish; 
       // if (a.species == "fish" && (Fish) a.CanSplash) 
       if (fish.CanSplash) 
       { 
        Console.WriteLine("{0} can splash", a.Name); 
       } 
      } 
     } 
    } 

方法をすることができますが、動物にアクセスすることはできませんためは//、静的なキーワードを削除(または動物が静的でなければなりません)の

チェックタイプを、そして自分の行動を取ります

ところで、Animalは抽象クラスで、Fishクラスの抽象メソッドの実装はどこですか?

+0

この場合、タイプチェックを2回行う必要はありません。あなたのアプローチは古いパターン 'if(aはSomeClass){var c =(SomeClass)a; ... 'は非効率的です。 – abto

+0

私はOPの実装の範囲に集中し、必要なアクションを取るために1回だけ(2回ではなく)タイプをチェックします。 Interfaceを使用した変更は、大規模な複雑なモデルには適しています。単純なクラスモデルでは必要ありません。 私は以下を使用することができます:if(splasher?.CanSplash :) :) –

+0

あなたの "集中力"は安全な型キャストがしているものです。あなたの 'if(a is Fish)'ステートメントは、特に新しいC#6機能を使いたい場合は不要です: 'var fish = a as Fish; if(fish?.CanSplash)... '。そして、あなたが正しいです、インターフェイスは単純なデザインでは必要ではありませんが、私はこれを私の答えで述べました... – abto

関連する問題