Ostatnio współpracuję z dostawcami i natknąłem się na interesującą sytuację, w której chciałem mieć klasę abstrakcyjną z abstrakcyjną metodą statyczną. Przeczytałem kilka postów na ten temat i ma to sens, ale czy istnieje jakieś przyjemne, jasne wytłumaczenie?
c#
.net
language-design
lomaxx
źródło
źródło
Odpowiedzi:
Metody statyczne nie są tworzone jako takie, są one po prostu dostępne bez odwołania do obiektu.
Wywołanie metody statycznej odbywa się poprzez nazwę klasy, a nie przez odwołanie do obiektu, a kod języka pośredniego (IL), aby ją wywołać, wywoła metodę abstrakcyjną poprzez nazwę klasy, która ją zdefiniowała, niekoniecznie nazwę klasa, której użyłeś.
Pokażę przykład.
Z następującym kodem:
Jeśli zadzwonisz do B.Test, wykonaj następujące czynności:
Zatem rzeczywisty kod w metodzie Main wygląda następująco:
Jak widać, wywoływane jest A.Test, ponieważ to klasa A go zdefiniowała, a nie B.Test, nawet jeśli można w ten sposób napisać kod.
Gdybyś miał typy klas , takie jak w Delphi, w których możesz utworzyć zmienną odnoszącą się do typu, a nie obiektu, miałbyś więcej zastosowania dla wirtualnych, a tym samym abstrakcyjnych metod statycznych (a także konstruktorów), ale nie są one dostępne i dlatego wywołania statyczne nie są wirtualne w .NET.
Zdaję sobie sprawę, że projektanci IL mogliby umożliwić kompilację kodu w celu wywołania B.Test i rozwiązania wywołania w czasie wykonywania, ale nadal nie byłby wirtualny, ponieważ nadal musiałbyś tam napisać jakąś nazwę klasy.
Metody wirtualne, a tym samym abstrakcyjne, są użyteczne tylko wtedy, gdy używasz zmiennej, która w czasie wykonywania może zawierać wiele różnych typów obiektów, a zatem chcesz wywołać odpowiednią metodę dla bieżącego obiektu, który masz w zmiennej. W przypadku metod statycznych i tak musisz przejść przez nazwę klasy, więc dokładna metoda do wywołania jest znana w czasie kompilacji, ponieważ nie może i nie zmieni się.
Dlatego wirtualne / abstrakcyjne metody statyczne nie są dostępne w .NET.
źródło
Test()
jestA
raczej abstrakcyjna i potencjalnie zdefiniowana wB
. \Car
typ z wirtualną statycznąCreateFromDescription
metodą fabryczną, wówczas kod, który akceptujeCar
typ ogólny ograniczony,T
mógłby wywołaćT.CreateFromDescription
samochód typuT
. Taki konstrukt mógłby być obsługiwany całkiem dobrze w CLR, gdyby każdy typ, który zdefiniował taką metodę, posiadał statyczną instancję singleton klasy ogólnej klasy zagnieżdżonej, która zawierała wirtualne metody „statyczne”.Metody statyczne nie mogą być dziedziczone ani zastępowane, dlatego nie mogą być abstrakcyjne. Ponieważ metody statyczne są zdefiniowane na typie, a nie na instancji klasy, muszą być jawnie wywoływane dla tego typu. Więc jeśli chcesz wywołać metodę na klasie potomnej, musisz użyć jej nazwy, aby ją wywołać. To sprawia, że dziedziczenie jest nieistotne.
Załóżmy, że możesz na chwilę odziedziczyć metody statyczne. Wyobraź sobie ten scenariusz:
Jeśli wywołasz funkcję Base.GetNumber (), która metoda zostanie wywołana? Która wartość zwrócona? Bardzo łatwo zauważyć, że bez tworzenia instancji obiektów dziedziczenie jest raczej trudne. Metody abstrakcyjne bez dziedziczenia to tylko metody, które nie mają ciała, więc nie można ich nazwać.
źródło
int DoSomething<T>() where T:Base {return T.GetNumber();}
. Przydałoby się, gdybyDoSomething<Base>()
mógł zwrócić pięć, aDoSomething<Child2>()
dwa. Taka umiejętność byłaby przydatna nie tylko w przykładach zabawek, ale także w przypadku czegoś takiegoclass Car {public static virtual Car Build(PurchaseOrder PO);}
, w którym każda klasa wywodząca się z niegoCar
musiałaby zdefiniować metodę, która mogłaby zbudować instancję na podstawie zamówienia.Inny respondent (McDowell) powiedział, że polimorfizm działa tylko dla instancji obiektów. To powinno być kwalifikowane; istnieją języki, które traktują klasy jako instancje typu „Class” lub „Metaclass”. Te języki obsługują polimorfizm zarówno dla metod instancji, jak i klas (statycznych).
C #, podobnie jak wcześniej Java i C ++, nie jest takim językiem;
static
parametr jest używany do oznaczenia wyraźnie, że metoda jest statycznie związana zamiast dynamiczny / wirtualny.źródło
Oto sytuacja, w której zdecydowanie istnieje potrzeba dziedziczenia pól i metod statycznych:
źródło
legs
powinna być statyczną abstrakcyjną własnością.Aby dodać do poprzednich wyjaśnień, statyczne wywołania metod są powiązane z określoną metodą w czasie kompilacji , co raczej wyklucza zachowanie polimorficzne.
źródło
W rzeczywistości zastępujemy metody statyczne (w delphi), jest to trochę brzydkie, ale działa dobrze dla naszych potrzeb.
Używamy go, aby klasy mogły mieć listę dostępnych obiektów bez instancji klasy, na przykład mamy metodę, która wygląda następująco:
Jest to brzydkie, ale konieczne, w ten sposób możemy utworzyć instancję tylko tego, co jest potrzebne, zamiast tworzenia instancji wszystkich klas tylko w celu wyszukiwania dostępnych obiektów.
To był prosty przykład, ale sama aplikacja jest aplikacją klient-serwer, która ma wszystkie klasy dostępne na jednym serwerze i wielu różnych klientów, którzy mogą nie potrzebować wszystkiego, co serwer ma i nigdy nie będzie potrzebować instancji obiektu.
Jest to o wiele łatwiejsze w utrzymaniu niż posiadanie jednej aplikacji serwera dla każdego klienta.
Mam nadzieję, że przykład był jasny.
źródło
Metody abstrakcyjne są domyślnie wirtualne. Metody abstrakcyjne wymagają wystąpienia, ale metody statyczne nie mają wystąpienia. Tak więc możesz mieć metodę statyczną w klasie abstrakcyjnej, to po prostu nie może być statyczna abstrakcja (lub abstrakcyjna statyczność).
źródło