Ich evaluiere ein Open-Source-CMS namens Piranha ( http://piranhacms.org/ ) zur Verwendung in einem meiner Projekte. Ich fand den folgenden Code interessant und zumindest für mich etwas verwirrend. Können mir einige helfen, zu verstehen, warum die Klasse von einer Basis desselben Typs erbt?
public abstract class BasePage<T> : Page<T> where T : BasePage<T>
{
/// <summary>
/// Gets/sets the page heading.
/// </summary>
[Region(SortOrder = 0)]
public Regions.PageHeading Heading { get; set; }
}
Wenn eine Klasse von BasePage<T>
definiert wird, warum von erben Page<T> where T: BasePage<T>
? Welchem spezifischen Zweck dient es?
c#
architecture
.net
cms
Xami Yen
quelle
quelle
Antworten:
Es ist nicht, es erbt von
Page<T>
, aber esT
ist darauf beschränkt, durch einen Typ parametrisiert zu werden, von dem es abgeleitet istBasePage<T>
.Um zu schließen, warum, müssen Sie sich ansehen, wie der Typparameter
T
tatsächlich verwendet wird. Nach einigem Graben werden Sie auf diese Klasse stoßen, wenn Sie die Vererbungskette hinaufsteigen:( Github )
Soweit ich sehen kann, besteht der einzige Zweck der generischen Einschränkung darin, sicherzustellen, dass die
Create
Methode den am wenigsten abstrakten Typ zurückgibt, der möglich ist.Ich bin mir nicht sicher, ob es sich lohnt, aber vielleicht steckt ein guter Grund dahinter, oder es könnte nur der Einfachheit halber sein, oder vielleicht steckt nicht allzu viel Substanz dahinter und es ist nur ein überaus ausgeklügelter Weg, eine Besetzung zu vermeiden (Übrigens, ich Ich will damit nicht andeuten, dass das hier der Fall ist. Ich sage nur, dass die Leute das manchmal tun.
Beachten Sie, dass dies ihnen nicht erlaubt, Reflexionen zu vermeiden. Dies
api.Pages
ist ein Repository von Seiten, die abgerufentypeof(T).Name
und alstypeId
an diecontentService.Create
Methode übergeben werden ( siehe hier ).quelle
Eine gebräuchliche Verwendung davon hängt mit dem Konzept der Selbsttypen zusammen: ein Typparameter, der in den aktuellen Typ aufgelöst wird. Angenommen, Sie möchten eine Schnittstelle mit einer
clone()
Methode definieren. Dieclone()
Methode muss immer eine Instanz der Klasse zurückgeben, für die sie aufgerufen wurde. Wie deklarieren Sie diese Methode? In einem generischen System mit Selbsttypen ist dies einfach. Sie sagen nur, es kehrt zurückself
. Wenn ich also eine Klasse habeFoo
, muss die Klonmethode deklariert werden, um zurückzukehrenFoo
. In Java und (von einer flüchtigen Suche) C # ist dies keine Option. Stattdessen sehen Sie Deklarationen, die denen in dieser Klasse entsprechen. Es ist wichtig zu verstehen, dass dies nicht dasselbe ist wie ein Selbsttyp, und die darin enthaltenen Einschränkungen sind schwächer. Wenn Sie eineFoo
und eineBar
Klasse haben, von denen beide abgeleitet sindBasePage
, Sie können (wenn ich mich nicht irre) definieren, dass Foo durch parametrisiert wirdBar
. Das mag nützlich sein, aber ich denke, normalerweise wird dies die meiste Zeit wie ein Selbsttyp verwendet, und es versteht sich von selbst, dass Sie es nicht tun sollten, obwohl Sie herumspielen und durch andere Typen ersetzen können. Ich habe vor langer Zeit mit dieser Idee herumgespielt, bin aber zu dem Schluss gekommen, dass sich die Mühe aufgrund der Einschränkungen von Java-Generika nicht gelohnt hat. C # -Generika sind natürlich umfassender ausgestattet, es scheint jedoch die gleiche Einschränkung zu geben.Ein anderes Mal wird dieser Ansatz verwendet, wenn Sie grafische Typen wie Bäume oder andere rekursive Strukturen erstellen. Die Deklaration ermöglicht es Typen, die Anforderungen von Page zu erfüllen, aber den Typ weiter zu verfeinern. Möglicherweise sehen Sie dies in einer Baumstruktur. Zum Beispiel
Node
könnte a parametrisiert werdenNode
, damit Implementierungen definieren können, dass es sich nicht nur um Bäume handelt, die einen Knotentyp enthalten, sondern um einen bestimmten Knotentyp (normalerweise einen eigenen Typ). Ich denke, das ist mehr, was hier vor sich geht.quelle
Als die Person, die den Code tatsächlich geschrieben hat, kann ich bestätigen, dass Filip korrekt ist und das selbstreferenzierende Generikum in der Tat eine Annehmlichkeit für die Bereitstellung einer typisierten Create-Methode für die Basisklasse darstellt.
Wie er erwähnt, wird immer noch viel nachgedacht, und am Ende wird nur der Name des Typs zum Auflösen des Seitentyps verwendet. Der Grund dafür ist, dass Sie auch dynamische Modelle laden können, dh das Modell materialisieren können, ohne Zugriff auf den CLR-Typ zu haben, der es ursprünglich erstellt hat.
quelle