Mam wyliczenie w przestrzeni nazw niskiego poziomu. Chciałbym zapewnić klasę lub wyliczenie w przestrzeni nazw średniego poziomu, która „dziedziczy” wyliczenie niskiego poziomu.
namespace low
{
public enum base
{
x, y, z
}
}
namespace mid
{
public enum consume : low.base
{
}
}
Mam nadzieję, że jest to możliwe, a może jakaś klasa, która może zająć miejsce enum konsumpcji, która zapewni warstwę abstrakcji dla enum, ale nadal pozwoli instancji tej klasy uzyskać dostęp do enum.
Myśli?
EDYCJA: Jednym z powodów, dla których nie zmieniłem tego na consts w klasach, jest to, że wyliczenie niskiego poziomu jest potrzebne przez usługę, którą muszę wykorzystać. Dostałem WSDL i XSD, które definiują strukturę jako wyliczenie. Usługi nie można zmienić.
Odpowiedzi:
To jest niemożliwe. Wyliczenia nie mogą dziedziczyć od innych wyliczeń. W rzeczywistości wszystkie wyliczenia muszą faktycznie dziedziczyć
System.Enum
. C # pozwala składni na zmianę reprezentacji wartości wyliczenia, która wygląda jak dziedziczenie, ale w rzeczywistości nadal dziedziczą one z System.enum.Szczegółowe informacje można znaleźć w sekcji 8.5.2 specyfikacji CLI . Istotne informacje ze specyfikacji
System.Enum
źródło
switch
sytuacji.Możesz osiągnąć to, co chcesz dzięki zajęciom:
Teraz możesz używać tych klas podobnie jak wtedy, gdy były one wyliczeniami:
Aktualizacja (po aktualizacji pytania):
Jeśli przypiszesz te same wartości int do stałych zdefiniowanych w istniejącym wyliczeniu, możesz rzutować między wyliczeniem i stałymi, np .:
źródło
Enum.GetValues(typeof(MyEnum)
void Test() { foreach (System.Reflection.PropertyInfo pi in typeof(Consume).GetProperties()) { Console.WriteLine(pi.Name); } }
Krótka odpowiedź brzmi: nie. Możesz trochę zagrać, jeśli chcesz:
Zawsze możesz zrobić coś takiego:
Ale to nie działa tak dobrze, ponieważ Base.A! = Consume.A
Zawsze możesz jednak zrobić coś takiego:
Aby przejść między bazą a konsumpcją ...
Możesz także rzucić wartości wyliczeń jako ints i porównać je jako ints zamiast enum, ale to też jest do bani.
Zwracana metoda rozszerzenia powinna mieć typ cast to T.
źródło
Base.A == (Base)Consume.A
int
miałoby dużo więcej sensu. Kiedy wyliczenie miałoby część ułamkową!?!?!Powyższe rozwiązania wykorzystujące klasy ze stałymi int nie mają bezpieczeństwa typu. To znaczy, możesz wymyślić nowe wartości, które nie zostały zdefiniowane w klasie. Ponadto nie można na przykład napisać metody przyjmującej jedną z tych klas jako dane wejściowe.
Musisz pisać
Istnieje jednak oparte na klasach rozwiązanie dawnych czasów Java, kiedy nie było dostępnych wyliczeń. Zapewnia to zachowanie prawie podobne do wyliczania. Jedynym zastrzeżeniem jest to, że tych stałych nie można użyć w instrukcji switch.
źródło
object
spowoduje, że wartości będą różne dla każdej instancji zestawu, więc nie będą mogły być serializowane.Ignorując fakt, że podstawa jest słowem zastrzeżonym, nie można dziedziczyć enum.
Najlepsze, co możesz zrobić, to coś takiego:
Ponieważ wszystkie są tego samego typu podstawowego (tj .: int), można przypisać wartość z wystąpienia jednego typu do drugiego, który jest rzutowany. Nie idealne, ale działa.
źródło
Wiem, że ta odpowiedź jest trochę spóźniona, ale tak właśnie skończyłem:
Jestem w stanie robić takie rzeczy jak:
źródło
Oto co zrobiłem. To, co zrobiłem inaczej, to użycie tej samej nazwy i
new
słowa kluczowego w „konsumpcji”enum
. Ponieważ nazwa tego samegoenum
jest taka sama, możesz po prostu bezmyślnie go używać i będzie dobrze. Plus dostajesz inteligencję. Musisz tylko ręcznie zadbać o to, aby ustawienia były kopiowane z bazy i aby były zsynchronizowane. Możesz w tym pomóc wraz z komentarzami do kodu. To kolejny powód, dla którego w bazie danychenum
zawsze przechowuję ciąg, a nie wartość. Ponieważ jeśli używasz automatycznie przypisywanych rosnących wartości liczb całkowitych, mogą one ulec zmianie z czasem.źródło
SmallMedium = 100,
), Aby zachować zgodność ze starszymi wersjami oprogramowania po dodaniu nowych wartości w klasie podstawowej. Na przykład dodanieHuge
rozmiaru do wyliczenia podstawowego przypisałoby4
jego wartość, ale4
jest już zajęteSmallMedium
w klasie pochodnej.Huge
klasy podstawowej wymagałoby wcześniejHuge
w podklasieSmallMedium
BaseBall
może nie być tutaj najmądrzejszą nazwą. To wprowadza zamieszanie. Ponieważ baseball jest w rzeczywistości rzeczą. Jeśli tęsknisz za tym, że to tylko podstawowa klasa piłki, wygląda to dziwnie, że siatkówka dziedziczy po fizycznie mniejszym baseballu :). Moja sugestia to po prostu użyćBall
Alternatywne rozwiązanie
W mojej firmie unikamy „przeskakiwania projektów”, aby dostać się do nietypowych projektów niższego poziomu. Na przykład nasza warstwa prezentacji / interfejsu API może odwoływać się tylko do naszej warstwy domeny, a warstwa domeny może odwoływać się tylko do warstwy danych.
Jest to jednak problem, gdy istnieją wyliczenia, do których należy odwoływać się zarówno prezentacja, jak i warstwy domen.
Oto rozwiązanie, które wdrożyliśmy (do tej pory). Jest to całkiem dobre rozwiązanie i działa dobrze dla nas. Inne odpowiedzi dotyczyły tego wszystkiego.
Podstawową przesłanką jest to, że nie można dziedziczyć enum - ale klasy mogą. Więc...
Następnie, aby „odziedziczyć” wyliczenia w innym projekcie wyższego poziomu ...
Ma to trzy prawdziwe zalety ...
Aby odwołać się do wyliczeń w pierwszym projekcie , możesz użyć prefiksu klasy: BaseEnums.StatusType.Pending lub dodać „przy użyciu statycznego BaseEnums;” oświadczenie dotyczące twoich zastosowań.
Jednak w drugim projekcie dotyczącym odziedziczonej klasy nie mogłem uzyskać podejścia „za pomocą statycznego ...” , więc wszystkie odniesienia do „dziedziczonych wyliczeń” byłyby poprzedzone klasą, np. SubEnums.StatusType.Pending . Jeśli ktoś wymyśli sposób, aby pozwolić na użycie „statycznego” podejścia w drugim projekcie, daj mi znać.
Jestem pewien, że można to ulepszyć, aby uczynić go jeszcze lepszym - ale to faktycznie działa i zastosowałem to podejście w działających projektach.
Proszę głosować za tym, jeśli okaże się to pomocne.
źródło
Chciałem też przeciążenia wyliczenia i stworzył mieszankę odpowiedzią „Siedem” na tej stronie i odpowiedzią „Merlyn Morgan-Graham” na duplikatu stanowisko to , plus kilka ulepszeń.
Główne zalety mojego rozwiązania w porównaniu do innych:
Jest to gotowe rozwiązanie i może być bezpośrednio wprowadzone do projektu. Został zaprojektowany zgodnie z moimi potrzebami, więc jeśli nie lubisz niektórych jego części, po prostu zamień je na własny kod.
Po pierwsze, istnieje klasa podstawowa, z
CEnum
której wszystkie niestandardowe wyliczenia powinny dziedziczyć. Ma podstawową funkcjonalność, podobną doEnum
typu .net :Po drugie, oto 2 pochodne klasy Enum. Wszystkie klasy pochodne potrzebują podstawowych metod, aby działać zgodnie z oczekiwaniami. Jest to zawsze ten sam kod bojlera; Nie znalazłem jeszcze sposobu na przeniesienie go do klasy podstawowej. Kod pierwszego poziomu dziedziczenia różni się nieznacznie od wszystkich kolejnych poziomów.
Klasy zostały pomyślnie przetestowane przy użyciu następującego kodu:
źródło
Wyliczenia nie są rzeczywistymi klasami, nawet jeśli tak wyglądają. Wewnętrznie są one traktowane jak ich typ bazowy (domyślnie Int32). Dlatego możesz to zrobić tylko poprzez „kopiowanie” pojedynczych wartości z jednego wyliczenia do drugiego i rzutowanie ich na liczbę całkowitą w celu porównania ich pod kątem równości.
źródło
Wyliczeń nie można wyprowadzać z innych wyliczeń, ale tylko z int, uint, short, ushort, long, Ulong, byte i sbyte.
Jak powiedział Pascal, możesz użyć wartości lub stałych innych wyliczeń do zainicjowania wartości wyliczenia, ale o to chodzi.
źródło
inne możliwe rozwiązanie:
HTH
źródło
Nie jest to możliwe (jak już wspomniano @JaredPar). Próba obejścia tego logiką jest złą praktyką. Jeśli
base class
masz takienum
, powinieneś wypisać wszystkie możliweenum-values
opcje, a implementacja klasy powinna działać z wartościami, które zna.Np. Załóżmy, że masz klasę podstawową
BaseCatalog
i ma onaenum ProductFormats
(Digital
,Physical
). Wtedy możesz miećMusicCatalog
albo,BookCatalog
który może zawierać zarównoDigital
iPhysical
produkty, ale jeśli klasa jestClothingCatalog
, powinien zawierać tylkoPhysical
produkty.źródło
Zdaję sobie sprawę, że jestem trochę spóźniony na to przyjęcie, ale oto moje dwa centy.
Wszyscy wiemy, że środowisko nie obsługuje Enum. W tym wątku zasugerowano kilka bardzo interesujących obejść, ale żadne z nich nie przypominało tego, czego szukałem, więc sam to zrobiłem.
Przedstawiamy: ObjectEnum
Możesz sprawdzić kod i dokumentację tutaj: https://github.com/dimi3tron/ObjectEnum .
A pakiet tutaj: https://www.nuget.org/packages/ObjectEnum
Lub po prostu zainstaluj:
Install-Package ObjectEnum
W skrócie,
ObjectEnum<TEnum>
działa jak opakowanie dla każdego wyliczenia. Przesłaniając GetDefinedValues () w podklasach, można określić, które wartości wyliczeniowe są poprawne dla tej konkretnej klasy.Dodano szereg przeciążeń operatora, aby utworzyć
ObjectEnum<TEnum>
instancja zachowywała się tak, jakby była instancją bazowego wyliczenia, pamiętając o ograniczeniach dotyczących zdefiniowanych wartości. Oznacza to, że możesz łatwo porównać instancję do wartości int lub enum, a tym samym użyć jej w przypadku przełącznika lub dowolnego innego warunku.Chciałbym odwołać się do wzmianki o repozytorium github powyżej w celu uzyskania przykładów i dalszych informacji.
Mam nadzieję, że uznasz to za przydatne. Skomentuj lub otwórz problem w witrynie github, aby uzyskać dalsze przemyślenia lub komentarze.
Oto kilka krótkich przykładów tego, co możesz zrobić
ObjectEnum<TEnum>
:źródło
Możesz wykonywać dziedziczenie w enum, jednak jest ono ograniczone tylko do następujących typów. int, uint, byte, sbyte, short, ushort, long, ulong
Na przykład
źródło