以下は、他のいくつかの回答の最良の側面のいくつかと、必要なタイプのプロパティをCat
持つという重要な側面を可能にするテクニックを組み合わせたものですが、それを返すことができるのは、具体的には。Excrement
RadioactivePoo
Poo
AnimalBase
Cat
呼び出し元は、実装に存在していてもジェネリックを使用する必要はありません。また、特別な名前を付けるために別の名前の関数を呼び出す必要もありません。 Poo
。
中間クラスAnimalWithSpecialisations
は、Excrement
プロパティをシールするためだけに機能SpecialPoo
し、非公開プロパティを介して、派生戻り値の型のプロパティAnimalWithSpecialPoo<TPoo>
を持つ派生クラスに接続しExcrement
ます。
が何らかの形で特別なCat
唯一の動物である場合Poo
、またはのタイプをExcrement
の主要な定義機能にしたくない場合はCat
、中間のジェネリッククラスを階層内でスキップできるため、Cat
から直接派生しますがAnimalWithSpecialisations
、いくつかの異なる動物であり、その主な特徴は、それらPoo
が何らかの形で特別であるということです。「ボイラープレート」を中間クラスに分離すると、Cat
と、いくつかの追加の仮想関数呼び出しが発生しますがクラス自体をかなりクリーンます。
サンプルコードは、期待される操作のほとんどが「期待どおりに」機能することを示しています。
public interface IExcretePoo<out TPoo>
where TPoo : Poo
{
TPoo Excrement { get; }
}
public class Poo
{ }
public class RadioactivePoo : Poo
{ }
public class AnimalBase : IExcretePoo<Poo>
{
public virtual Poo Excrement { get { return new Poo(); } }
}
public class Dog : AnimalBase
{
}
public abstract class AnimalWithSpecialisations : AnimalBase
{
public sealed override Poo Excrement { get { return SpecialPoo; } }
protected virtual Poo SpecialPoo { get { return base.Excrement; } }
}
public abstract class AnimalWithSpecialPoo<TPoo> : AnimalWithSpecialisations, IExcretePoo<TPoo>
where TPoo : Poo
{
sealed protected override Poo SpecialPoo { get { return Excrement; } }
public new abstract TPoo Excrement { get; }
}
public class Cat : AnimalWithSpecialPoo<RadioactivePoo>
{
public override RadioactivePoo Excrement { get { return new RadioactivePoo(); } }
}
class Program
{
static void Main(string[] args)
{
Dog dog = new Dog();
Poo dogPoo = dog.Excrement;
Cat cat = new Cat();
RadioactivePoo catPoo = cat.Excrement;
AnimalBase animal = cat;
Poo animalPoo = catPoo;
animalPoo = animal.Excrement;
AnimalWithSpecialPoo<RadioactivePoo> radioactivePooingAnimal = cat;
RadioactivePoo radioactivePoo = radioactivePooingAnimal.Excrement;
IExcretePoo<Poo> pooExcreter = cat;
IExcretePoo<RadioactivePoo> radioactivePooExcreter = cat;
animal = dog;
animalPoo = dogPoo;
pooExcreter = dog;
}