Mam kilka klas, które tak naprawdę nie potrzebują żadnego stanu. Z organizacyjnego punktu widzenia chciałbym umieścić je w hierarchii.
Ale wydaje się, że nie mogę zadeklarować dziedziczenia dla klas statycznych.
Coś w tym stylu:
public static class Base
{
}
public static class Inherited : Base
{
}
nie będzie działać.
Dlaczego projektanci języka zamknęli tę możliwość?
c#
inheritance
static
Użytkownik
źródło
źródło
Odpowiedzi:
Cytowanie stąd :
Inne opinie z kanału9
I jako cenny pomysł, Littleguru ma częściowe „obejście” tego problemu: wzór Singletona .
źródło
object
i każdy powinien to wiedzieć. Tak więc klasy statyczne zawsze dziedzicząobject
, bez względu na to, czy zostanie to określone jawnie, czy nie.Głównym powodem, dla którego nie można odziedziczyć klasy statycznej, jest to, że są one abstrakcyjne i zapieczętowane (zapobiega to również tworzeniu ich instancji).
Więc to:
kompiluje się do tej IL:
źródło
Pomyśl o tym w ten sposób: uzyskujesz dostęp do elementów statycznych za pomocą nazwy typu, w następujący sposób:
Gdybyś odziedziczył po tej klasie, musiałbyś uzyskać do niej dostęp poprzez nazwę nowego typu:
Zatem nowy element nie ma żadnych relacji z oryginałem, gdy jest używany w kodzie. Nie byłoby sposobu, aby wykorzystać jakąkolwiek relację dziedziczenia dla takich rzeczy jak polimorfizm.
Być może myślisz, że chcesz po prostu rozszerzyć niektóre przedmioty z oryginalnej klasy. W takim przypadku nic nie stoi na przeszkodzie, abyś po prostu użył członka oryginału w zupełnie nowym typie.
Być może chcesz dodać metody do istniejącego typu statycznego. Możesz to zrobić już za pomocą metod rozszerzenia.
Być może chcesz móc przekazać statyczną
Type
funkcję do funkcji w czasie wykonywania i wywołać metodę tego typu, nie wiedząc dokładnie, co robi ta metoda. W takim przypadku możesz użyć interfejsu.Ostatecznie tak naprawdę nie zyskujesz na odziedziczeniu klas statycznych.
źródło
SomeClass<T> where T:Foo
mógł uzyskać dostęp do elementówFoo
, a gdybyT
była klasa, która przesłoniłaby niektóre wirtualne elementy statyczneFoo
, klasa ogólna użyłaby tych przesłonięć. Prawdopodobnie byłoby nawet możliwe zdefiniowanie konwencji, dzięki której języki mogłyby to robić w sposób zgodny z obecnym CLR (np. Klasa z takimi elementami powinna zdefiniować chronioną klasę niestatyczną, która zawiera takie elementy instancji, wraz z polem statycznym z instancją tego typu).To, co chcesz osiągnąć za pomocą hierarchii klas, można osiągnąć jedynie poprzez przestrzeń nazw. Tak więc języki, które obsługują nazwy (np. C #), nie będą mogły wykorzystywać hierarchii klas klas statycznych. Ponieważ nie można utworzyć żadnej z klas, wystarczy hierarchiczna organizacja definicji klas, którą można uzyskać za pomocą przestrzeni nazw
źródło
Zamiast tego możesz użyć kompozycji ... pozwoli ci to uzyskać dostęp do obiektów klasy od typu statycznego. Ale nadal nie mogę zaimplementować interfejsów lub klas abstrakcyjnych
źródło
Chociaż można uzyskać dostęp do „odziedziczonych” elementów statycznych za pośrednictwem dziedziczonej nazwy klas, elementy statyczne nie są tak naprawdę dziedziczone. Po części dlatego nie mogą być wirtualne ani abstrakcyjne i nie można ich zastąpić. W twoim przykładzie, jeśli zadeklarujesz Base.Method (), kompilator i tak odwzoruje wywołanie na Inherited.Method () z powrotem na Base.Method (). Równie dobrze możesz wywołać funkcję Base.Method (). Możesz napisać mały test i zobaczyć wynik za pomocą Odbłyśnika.
Więc ... jeśli nie możesz dziedziczyć elementów statycznych, a jeśli klasy statyczne mogą zawierać tylko elementy statyczne, to co pożyteczne byłoby dziedziczenie klasy statycznej?
źródło
Hmmm ... czy byłoby znacznie inaczej, gdybyś miał klasy niestatyczne wypełnione metodami statycznymi ..?
źródło
Obejściem, które można zrobić, jest nieużywanie klas statycznych, ale ukrywanie konstruktora, więc elementy statyczne klas są jedyną dostępną poza klasą. Rezultatem jest dziedziczna „statyczna” klasa zasadniczo:
Niestety z powodu ograniczeń językowych „w fazie projektowania” nie możemy zrobić:
źródło
Możesz zrobić coś, co będzie wyglądać jak dziedziczenie statyczne.
Oto sztuczka:
Następnie możesz to zrobić:
Inherited
Klasa sama w sobie nie jest statyczna, ale nie pozwalają, aby go utworzyć. W rzeczywistości odziedziczył konstruktora statycznego, który budujeBase
, a wszystkie właściwości i metody sąBase
dostępne jako statyczne. Teraz pozostało już tylko zrobić statyczne opakowania dla każdej metody i właściwości, które należy udostępnić w kontekście statycznym.Są wady, takie jak potrzeba ręcznego tworzenia statycznych metod owijania i
new
słów kluczowych. Ale to podejście pomaga wspierać coś, co jest naprawdę podobne do dziedziczenia statycznego.PS Użyliśmy tego do tworzenia skompilowanych zapytań, które faktycznie można zastąpić ConcurrentDictionary, ale statyczne pole tylko do odczytu z jego bezpieczeństwem wątków było wystarczająco dobre.
źródło
Moja odpowiedź: zły wybór projektu. ;-)
To interesująca debata poświęcona wpływowi składni. Moim zdaniem rdzeniem tego argumentu jest to, że decyzja projektowa doprowadziła do zapieczętowanych klas statycznych. Skupiasz się na przejrzystości nazw klas statycznych pojawiających się na najwyższym poziomie zamiast ukrywania („mylenia”) za imionami dzieci? Można sobie wyobrazić implementację języka, która mogłaby uzyskać bezpośredni dostęp do bazy lub dziecka, co jest mylące.
Pseudo przykład, zakładający statyczne dziedziczenie, został w jakiś sposób zdefiniowany.
doprowadziłoby do:
co może (mogłoby?) wpłynąć na to samo miejsce do przechowywania
Bardzo mylące!
Ale poczekaj! Jak kompilator poradziłby sobie z MyStaticBase i MyStaticChild posiadającymi taki sam podpis zdefiniowany w obu? Jeśli dziecko zastąpi, niż mój powyższy przykład, NIE zmieniłoby tego samego magazynu, może? Prowadzi to do jeszcze większego zamieszania.
Uważam, że istnieje silne uzasadnienie przestrzeni informacyjnej dla ograniczonego dziedziczenia statycznego. Więcej o limitach wkrótce. Ten pseudokod pokazuje wartość:
Następnie otrzymujesz:
Sposób użycia wygląda następująco:
Osoba tworząca statyczne dziecko nie musi myśleć o procesie serializacji, o ile rozumie wszelkie ograniczenia, które mogą zostać nałożone na silnik serializacji platformy lub środowiska.
Statyka (singletony i inne formy „globałów”) często pojawiają się wokół pamięci konfiguracji. Dziedziczenie statyczne pozwoliłoby na czystą reprezentację tego rodzaju alokacji odpowiedzialności w składni w celu dopasowania do hierarchii konfiguracji. Chociaż, jak pokazałem, istnieje duże prawdopodobieństwo ogromnej dwuznaczności, jeśli zostaną zaimplementowane podstawowe koncepcje dziedziczenia statycznego.
Uważam, że właściwym wyborem projektowym byłoby umożliwienie dziedziczenia statycznego z określonymi ograniczeniami:
Nadal możesz zmienić ten sam sklep za pomocą ogólnego odniesienia
MyStaticBase<ChildPayload>.SomeBaseField
. Byłbyś jednak zniechęcony, ponieważ typ ogólny musiałby zostać określony. Natomiast odniesienie dziecko byłoby czystsze:MyStaticChild.SomeBaseField
.Nie jestem pisarzem kompilatorów, więc nie jestem pewien, czy coś mi brakuje na temat trudności we wdrażaniu tych ograniczeń w kompilatorze. To powiedziawszy, jestem głęboko przekonany, że istnieje przestrzeń informacyjna, która wymaga ograniczonego dziedziczenia statycznego, a podstawową odpowiedzią jest to, że nie możesz tego zrobić z powodu złego (lub zbyt prostego) wyboru projektu.
źródło
Klasy statyczne i elementy klasy służą do tworzenia danych i funkcji, do których można uzyskać dostęp bez tworzenia instancji klasy. Członków klasy statycznej można używać do oddzielania danych i zachowania niezależnego od tożsamości obiektu: dane i funkcje nie zmieniają się niezależnie od tego, co stanie się z obiektem. Klasy statyczne mogą być używane, gdy w klasie nie ma danych ani zachowań, które zależą od tożsamości obiektu.
Klasę można zadeklarować jako statyczną, co oznacza, że zawiera ona tylko elementy statyczne. Nie można użyć nowego słowa kluczowego do utworzenia instancji klasy statycznej. Klasy statyczne są ładowane automatycznie przez środowisko uruchomieniowe języka wspólnego CLR .NET Framework po załadowaniu programu lub przestrzeni nazw zawierającej klasę.
Użyj klasy statycznej, aby zawierać metody, które nie są powiązane z konkretnym obiektem. Na przykład częstym wymogiem jest utworzenie zestawu metod, które nie działają na danych instancji i nie są powiązane z konkretnym obiektem w kodzie. Możesz użyć klasy statycznej do przechowywania tych metod.
Oto główne cechy klasy statycznej:
Zawierają tylko elementy statyczne.
Nie można ich utworzyć.
Są zapieczętowane.
Nie mogą zawierać Konstruktorów instancji (Podręcznik programowania w języku C #).
Utworzenie klasy statycznej jest zatem zasadniczo tym samym, co utworzenie klasy zawierającej tylko elementy statyczne i prywatnego konstruktora. Prywatny konstruktor zapobiega tworzeniu instancji klasy.
Zaletą używania klasy statycznej jest to, że kompilator może sprawdzić, aby upewnić się, że żadne elementy instancji nie zostaną przypadkowo dodane. Kompilator zagwarantuje, że nie można utworzyć instancji tej klasy.
Klasy statyczne są zapieczętowane i dlatego nie można ich dziedziczyć. Nie mogą dziedziczyć po żadnej klasie oprócz Object. Klasy statyczne nie mogą zawierać konstruktora instancji; mogą jednak mieć statycznego konstruktora. Aby uzyskać więcej informacji, zobacz Konstruktory statyczne (Podręcznik programowania w języku C #).
źródło
Kiedy tworzymy klasę statyczną, która zawiera tylko elementy statyczne i konstruktora prywatnego. Jedynym powodem jest to, że konstruktor statyczny uniemożliwia utworzenie instancji klasy, w związku z czym nie możemy odziedziczyć klasy statycznej. Jedyny sposób, aby uzyskać dostęp do elementu klasa statyczna, używając samej nazwy klasy. Próba dziedziczenia klasy statycznej nie jest dobrym pomysłem.
źródło