Oceniam CMS typu open source o nazwie Piranha ( http://piranhacms.org/ ) do wykorzystania w jednym z moich projektów. Dla mnie poniższy kod był interesujący i nieco mylący. Czy ktoś może mi pomóc zrozumieć, dlaczego klasa dziedziczy po bazie tego samego typu?
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; }
}
Jeśli BasePage<T>
definiowana jest klasa , po co dziedziczyć Page<T> where T: BasePage<T>
? Jakiemu konkretnemu celowi to służy?
c#
architecture
.net
cms
Xami Yen
źródło
źródło
Odpowiedzi:
Nie jest, dziedziczy po
Page<T>
, aleT
sam w sobie jest sparametryzowany przez typ, z którego pochodziBasePage<T>
.Aby wywnioskować, dlaczego, musisz spojrzeć na to, jak
T
faktycznie używany jest parametr type . Po pewnym kopaniu, idąc w górę łańcucha spadkowego, natkniesz się na tę klasę:( github )
O ile widzę, jedynym celem ogólnego ograniczenia jest upewnienie się, że
Create
metoda zwraca możliwie najmniej abstrakcyjny typ.Nie jestem jednak pewien, czy warto, ale może jest za tym jakiś dobry powód lub może to być tylko dla wygody, a może nie kryje się za tym zbyt wiele substancji i to po prostu zbyt skomplikowany sposób na uniknięcie obsady (BTW, ja nie sugeruję, że tak jest w tym przypadku, mówię tylko, że ludzie czasem tak robią).
Należy pamiętać, że to nie pozwala im uniknąć refleksji - w
api.Pages
to repozytorium stron, które uzyskujetypeof(T).Name
i przekazuje go jakotypeId
docontentService.Create
metody ( patrz tutaj ).źródło
Jedno z powszechnych zastosowań tego jest związane z koncepcją typów własnych: parametr typu, który jest rozwiązywany do bieżącego typu. Powiedzmy, że chcesz zdefiniować interfejs za pomocą
clone()
metody.clone()
Metoda musi zawsze powrócić instancję klasy, w którym została wywołana. Jak deklarujesz tę metodę? W systemie generycznym, który ma własny typ, jest to łatwe. Po prostu mówisz, że powracaself
. Więc jeśli mam klasęFoo
, metoda klonowania musi zostać zadeklarowana jako zwracanaFoo
. W Javie i (z pobieżnego wyszukiwania) C # nie jest to opcja. Zamiast tego widzisz deklaracje podobne do tego, co widzisz w tej klasie. Ważne jest, aby zrozumieć, że nie jest to to samo, co samokreślenie, a ograniczenia, które zapewnia, są słabsze. Jeśli masz klasęFoo
i, zBar
której oba pochodząBasePage
, możesz (jeśli się nie mylę) zdefiniować Foo do parametryzacjiBar
. Może to być przydatne, ale myślę, że zazwyczaj przez większość czasu będzie to używane jako własny typ i zrozumiałe jest, że nawet jeśli możesz wygłupiać się i zastępować innymi typami, nie należy tego robić. Bawiłem się z tym pomysłem dawno temu, ale doszedłem do wniosku, że nie było to warte wysiłku, ponieważ ograniczenia generyczne Java. Generyczne C # są oczywiście w pełni funkcjonalne, ale wydaje się, że ma to samo ograniczenie.Innym razem stosuje się to podejście, gdy budujesz typy wykresów, takie jak drzewa lub inne rekurencyjne struktury. Deklaracja pozwala typom spełniać wymagania strony, ale dodatkowo uściśla typ. Możesz to zobaczyć w strukturze drzewa. Na przykład a
Node
można sparametryzować,Node
aby umożliwić implementacjom zdefiniowanie, że nie są to tylko Drzewa zawierające dowolny typ Węzła, ale określony podtyp Węzła (zwykle ich własny typ). Myślę, że więcej o tym tu chodzi.źródło
Będąc osobą, która faktycznie napisała kod, mogę potwierdzić, że Filip jest poprawny, a ogólny odnośnik ogólny jest w rzeczywistości wygodą dla zapewnienia typowej metody Create w klasie podstawowej.
Jak wspomina, wciąż wiele się zastanawia, a na końcu tylko nazwa typu jest używana do rozwiązania typu strony. Powodem tego jest to, że można również ładować modele dynamiczne, tj. Zmaterializować model bez dostępu do typu CLR, który go utworzył.
źródło