をwoofingされ感じていますこの回答では、属性ベースのソリューションを提示します。いくつかの側面では、@Drakenによって提案された解決策よりも保守が簡単かもしれませんが、他の面ではそれはあまり有用ではありません。
アトリビュートとしてマークするために、アトリビュートを持つペットメソッドに注釈を付けるアイデア。私はその属性を非常にシンプルにしました。それは、追加のメタ情報を持たない唯一のマーカーです。
IteratePetAbilities()
の方法は、ペットの能力にアクセスするための重要な方法です。これは、リフレクションを使用して、能力属性でマークされたメソッドを見つけ出し、それらを呼び出す。
// Note: Target method is required to have an empty parameter list
[AttributeUsage(AttributeTargets.Method)]
public sealed class PetAbilityAttribute : Attribute
{
}
public class MyPets
{
public MyPets()
{
Pets = new List<Pet>();
}
public ICollection<Pet> Pets { get; set; }
// Discover PetAbilityAttribute methods on the concrete pet type and invoke them dynamically
public void IteratePetAbilities()
{
foreach (var pet in Pets)
{
Console.WriteLine("Pet '" + pet.PetName + "' enters the stage");
var abilities = pet.GetType().GetMethods().Where(x => x.GetCustomAttributes(typeof(PetAbilityAttribute), true).Any());
foreach (var abilityMethod in abilities)
{
Console.Write("# {0,12}() # ", abilityMethod.Name);
abilityMethod.Invoke(pet, new object[] { });
}
Console.WriteLine();
}
}
}
public abstract class Pet
{
public string PetName { get; set; }
[PetAbility]
public abstract void MakeNoise();
// Note: this is not marked as an ability here
public abstract void GoSleep();
}
public class Dog : Pet
{
[PetAbility] // no effect, since base already has this attribute
public override void MakeNoise()
{
Console.WriteLine("Says woof");
}
// not marked as an ability
public override void GoSleep()
{
Console.WriteLine("Goes to the dogs house and sleeps");
}
}
public class Terrier : Dog
{
[PetAbility]
public void HuntACat()
{
Console.WriteLine("Starts running after a poor little cat");
}
[PetAbility] // Unlike a regular dog, the Terrier goes to sleep by ability :)
public override void GoSleep()
{
base.GoSleep();
}
}
public class Cat : Pet
{
public override void MakeNoise()
{
Console.WriteLine("Says meow");
}
[PetAbility]
public void ClimbTree()
{
Console.WriteLine("Climbs a tree and is to scared to return on its own");
}
[PetAbility] // makes GoSleep an ability only for cats, even though the method exists in base class
public override void GoSleep()
{
Console.WriteLine("Refuses to sleep and starts sharpening its claws");
}
}
class Program
{
static void Main(string[] args)
{
var myPets = new MyPets();
myPets.Pets.Add(new Cat() { PetName = "Super Cat" });
myPets.Pets.Add(new Dog() { PetName = "Little Dog" });
myPets.Pets.Add(new Terrier() { PetName = "Hunter" });
myPets.IteratePetAbilities();
}
}
出力
Pet 'Super Cat' enters the stage
# MakeNoise() # Says meow
# ClimbTree() # Climbs a tree and is to scared to return on its own
# GoSleep() # Refuses to sleep and starts sharpening its claws
Pet 'Little Dog' enters the stage
# MakeNoise() # Says woof
Pet 'Hunter' enters the stage
# HuntACat() # Starts running after a poor little cat
# GoSleep() # Goes to the dogs house and sleeps
# MakeNoise() # Says woof
プロ
- 関係なく、それはサブクラス階層(単一のポイントにネストされているか深く、任意の
Pet
サブクラスで新しい能力を追加するのは簡単ではありませんコード変更の内容)
コン
- は妥当性が施行されなければならない場合
- が複雑になる反射を使用します(たとえば、属性が入力パラメータを持つメソッドに適用された場合にどのような?)。
- 一部の人々は、それが時間のバインディングをコンパイルよりも遅いと言う(私は自分自身を測定していなかったが、私はそれを信じる傾向にある)特定の中
- 限定制御(たとえば、出力したい場合は、ペットの能力ため、追加の作業が必要です)
複数の能力との間の相互依存関係に適用されますDIT
サイドノート:オーバーライドメソッドは属性でマークされていないため、
(代わりにtrue
の)x.GetCustomAttributes(typeof(PetAbilityAttribute), false)
場合にはIteratePetAbilities()
で呼び出され、その後Cat.MakeNoise
は、発見されません。
「ペット」と「動物」は同じクラスを意味すると思いますか? 'MakeNoise()'と 'ClimbTree()'を呼び出す 'MyPets'のセマンティックコンテキストは何かを説明する必要があります。そうであれば、「ペット」には1つの重要な能力があります。それを基本クラスに抽象化することができます。あなたのペットの能力モデルが異なる場合、他のアプローチがあります。 – grek40
'Dog'と' Cat'の両方が 'makeNoise()'メソッドでそれを継承するように、 'Pet'(またはインターフェース)の抽象基本クラスを使います。次に、あなたの反復中に 'makeNoise()'を呼び出して、それらが 'Cat'のサブクラスかどうかを確認し、そうであれば' climbTree() 'メソッドを呼び出します。 [オブジェクトのキャストを扱うのはここを参照](http:// stackoverflow。実際のタイプのキャストオブジェクト)と[タイプのチェックについてはこちらを参照してください](http://stackoverflow.com/questions/2742276/how-do-i- com/questions/12234097/how-to-its-actual-type)サブタイプまたはオブジェクトのタイプのチェック) – Draken