Im Folgenden werden einige der besten Aspekte mehrerer anderer Antworten sowie eine Technik kombiniert, um den Schlüsselaspekt Cat
einer Excrement
Eigenschaft des erforderlichen RadioactivePoo
Typs zu ermöglichen. Sie können dies jedoch nur dann zurückgeben, Poo
wenn wir nur wissen, dass wir eine AnimalBase
eher als haben speziell aCat
.
Aufrufer müssen weder Generika verwenden, obwohl sie in den Implementierungen vorhanden sind, noch eine Funktion mit einem anderen Namen aufrufen, um etwas Besonderes zu erhalten Poo
.
Die Zwischenklasse AnimalWithSpecialisations
dient nur zum Versiegeln der Excrement
Eigenschaft und verbindet sie über eine nicht öffentliche SpecialPoo
Eigenschaft mit der abgeleiteten Klasse, AnimalWithSpecialPoo<TPoo>
die eine Excrement
Eigenschaft eines abgeleiteten Rückgabetyps hat.
Wenn Cat
es das einzige Tier Poo
ist, das in irgendeiner Weise etwas Besonderes ist, oder wenn wir nicht möchten, dass der Typ Excrement
das Hauptdefinitionsmerkmal von a ist Cat
, könnte die generische Zwischenklasse in der Hierarchie übersprungen werden, sodass sie Cat
direkt von abgeleitet wird AnimalWithSpecialisations
, aber wenn vorhanden Es gibt mehrere verschiedene Tiere, deren Hauptmerkmal darin besteht, dass sie Poo
in irgendeiner Weise etwas Besonderes sind. Die Aufteilung der "Kesselplatte" in Zwischenklassen hilft dabei, die Tiere zu haltenCat
Klasse selbst ziemlich sauber , wenn auch auf Kosten zusätzlicher virtueller Funktionsaufrufe.
Der Beispielcode zeigt, dass die meisten erwarteten Vorgänge "wie erwartet" funktionieren.
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;
}