Mam następujące wyliczenie:
public enum AuthenticationMethod
{
FORMS = 1,
WINDOWSAUTHENTICATION = 2,
SINGLESIGNON = 3
}
Problemem jest jednak to, że potrzebuję słowa „FORMULARZE”, gdy pytam o AuthenticationMethod.FORMS, a nie identyfikator 1.
Znalazłem następujące rozwiązanie tego problemu ( link ):
Najpierw muszę utworzyć niestandardowy atrybut o nazwie „StringValue”:
public class StringValue : System.Attribute
{
private readonly string _value;
public StringValue(string value)
{
_value = value;
}
public string Value
{
get { return _value; }
}
}
Następnie mogę dodać ten atrybut do mojego modułu wyliczającego:
public enum AuthenticationMethod
{
[StringValue("FORMS")]
FORMS = 1,
[StringValue("WINDOWS")]
WINDOWSAUTHENTICATION = 2,
[StringValue("SSO")]
SINGLESIGNON = 3
}
I oczywiście potrzebuję czegoś, aby odzyskać StringValue:
public static class StringEnum
{
public static string GetStringValue(Enum value)
{
string output = null;
Type type = value.GetType();
//Check first in our cached results...
//Look for our 'StringValueAttribute'
//in the field's custom attributes
FieldInfo fi = type.GetField(value.ToString());
StringValue[] attrs =
fi.GetCustomAttributes(typeof(StringValue),
false) as StringValue[];
if (attrs.Length > 0)
{
output = attrs[0].Value;
}
return output;
}
}
Dobrze, że teraz mam narzędzia do uzyskania wartości ciągu dla modułu wyliczającego. Następnie mogę użyć tego w następujący sposób:
string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);
Dobra, teraz wszystkie z nich działają jak urok, ale uważam, że to dużo pracy. Zastanawiałem się, czy istnieje na to lepsze rozwiązanie.
Próbowałem też czegoś ze słownikiem i właściwościami statycznymi, ale to też nie było lepsze.
this
przedEnum
metodą statyczną. Potem możesz zrobićAuthenticationMethod.Forms.GetStringValue();
Odpowiedzi:
Wypróbuj wzór typu bezpieczny enum .
Zaktualizuj Konwersję typu Jawnego (lub niejawnego) można wykonać za pomocą
dodanie pola statycznego z mapowaniem
wypełnianie tego mapowania w konstruktorze instancji
i dodanie operatora konwersji typu zdefiniowanego przez użytkownika
źródło
Użyj metody
jak w (Załóżmy, że
Shipper
Enum jest zdefiniowane)Istnieje również szereg innych metod statycznych w klasie Enum, które warto zbadać ...
źródło
Możesz odwoływać się do nazwy zamiast wartości, używając ToString ()
Dokumentacja jest tutaj:
http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx
... a jeśli nazwiesz swoje wyliczenia w Pascal Case (tak jak ja - na przykład ThisIsMyEnumValue = 1 itd.), możesz użyć bardzo prostego wyrażenia regularnego do wydrukowania przyjaznego formularza:
które można łatwo wywołać z dowolnego ciągu:
Wyjścia:
Oszczędza to biegania po domach, tworzenia niestandardowych atrybutów i dołączania ich do wyliczeń lub używania tabel odnośników do łączenia wartości wyliczenia z przyjaznym ciągiem znaków, a co najważniejsze, sam się zarządza i można go stosować na dowolnym ciągu sprawy Pascala, który jest nieskończony bardziej wielokrotnego użytku. Oczywiście nie pozwala ci to mieć innej przyjaznej nazwy niż twoje wyliczenie, które zapewnia twoje rozwiązanie.
Podoba mi się jednak twoje oryginalne rozwiązanie w przypadku bardziej złożonych scenariuszy. Możesz pójść o krok dalej i uczynić GetStringValue metodą rozszerzenia Twojego wyliczenia, a wtedy nie będziesz musiał odwoływać się do niego jak StringEnum.GetStringValue ...
Możesz wtedy uzyskać do niego łatwy dostęp bezpośrednio z instancji enum:
źródło
"(?!^)([^A-Z])([A-Z])", "$1 $2"
. Tak sięHereIsATEST
stajeHere Is ATEST
.Niestety refleksja w celu uzyskania atrybutów na wyliczeniach jest dość powolna:
Zobacz to pytanie: Czy ktoś zna szybki sposób na uzyskanie niestandardowych atrybutów dla wartości wyliczeniowej?
.ToString()
Jest dość powolna na teksty stałe też.Możesz jednak pisać metody rozszerzeń dla wyliczeń:
To nie jest świetne, ale będzie szybkie i nie wymaga refleksji dla atrybutów lub nazwy pola.
Aktualizacja C # 6
Jeśli możesz użyć C # 6, nowy
nameof
operator działa dla wyliczeń, więcnameof(MyEnum.WINDOWSAUTHENTICATION)
zostanie przekonwertowany"WINDOWSAUTHENTICATION"
na czas kompilacji , dzięki czemu będzie to najszybszy sposób na uzyskanie nazw wyliczeń.Zauważ, że to przekształci jawny wyliczenie w wstawioną stałą, więc nie działa dla wyliczeń, które masz w zmiennej. Więc:
Ale...
źródło
Używam metody rozszerzenia:
Teraz udekoruj za
enum
pomocą:Kiedy zadzwonisz
AuthenticationMethod.FORMS.ToDescription()
dostaniesz"FORMS"
.źródło
using System.ComponentModel;
także dodać , ta metoda działa tylko wtedy, gdy chcesz, aby wartość ciągu była taka sama jak nazwa Enum. OP chciał innej wartości.AuthenticationMethod.FORMS.ToDescription()
?Po prostu użyj
ToString()
metodyAby odwołać się do ciągu
Tomato
, po prostu użyjźródło
.ToString()
wartość inną niż wartość przyjazna dla użytkownika, której potrzebujesz.any fruit = any.Tomato;
string tomato = fruit.ToString();
Bardzo proste rozwiązanie tego problemu. Net 4.0 lub nowszy. Nie jest potrzebny żaden inny kod.
Aby uzyskać ciąg o po prostu użyj:
lub
Wartość będzie „Aktywna” lub „Zarchiwizowana”.
Aby zobaczyć różne formaty ciągów („f” z góry) podczas wywoływania,
Enum.ToString
zobacz stronę Ciągi formatowania wyliczeńźródło
Korzystam z atrybutu Opis z przestrzeni nazw System.ComponentModel. Po prostu udekoruj wyliczenie, a następnie użyj tego kodu, aby go odzyskać:
Jako przykład:
Ten kod ładnie obsługuje wyliczenia, w których nie potrzebujesz „przyjaznej nazwy”, i zwróci tylko .ToString () z wyliczenia.
źródło
Naprawdę podoba mi się odpowiedź Jakuba Šturca, ale jej wadą jest to, że nie można jej użyć z instrukcją przełączania. Oto nieco zmodyfikowana wersja jego odpowiedzi, której można użyć z instrukcją switch:
Dzięki temu zyskujesz wszystkie korzyści z odpowiedzi Jakuba Šturca, a ponadto możemy go użyć z instrukcją switch w następujący sposób:
źródło
public static int nextAvailable { get; private set; }
następnie w konstruktorzethis.Value = nextAvailable++;
=
operatora, aby umożliwić przełączenie do pracy? Zrobiłem to w VB i mogę teraz używać tego wselect case
zestawieniu.Używam kombinacji kilku powyższych sugestii w połączeniu z pewnym buforowaniem. Teraz wpadłem na pomysł z jakiegoś kodu, który znalazłem gdzieś w sieci, ale nie pamiętam, skąd go wziąłem ani go nie znalazłem. Jeśli więc ktoś znajdzie coś, co wygląda podobnie, prosimy o komentarz z tym opisem.
W każdym razie użycie obejmuje konwertery typów, więc jeśli jesteś powiązany z interfejsem użytkownika, „po prostu działa”. Wzorzec Jakuba można rozszerzyć w celu szybkiego wyszukiwania kodu, inicjując z konwertera typów na metody statyczne.
Podstawowe użycie wyglądałoby tak
Kod niestandardowego konwertera typu wyliczeniowego wygląda następująco:
}
źródło
W swoim pytaniu nigdy nie powiedziałeś, że naprawdę potrzebujesz wszędzie wartości liczbowej wyliczenia.
Jeśli nie potrzebujesz i potrzebujesz tylko wyliczenia typu string (który nie jest typem integralnym, więc nie może być podstawą wyliczenia), oto sposób:
możesz użyć tej samej składni, co enum, aby się do niego odwoływać
Będzie on nieco wolniejszy niż w przypadku wartości liczbowych (porównywanie ciągów zamiast liczb), ale po stronie plus nie używa odbicia (powolnego) w celu uzyskania dostępu do ciągu.
źródło
Jak rozwiązałem to jako metodę rozszerzenia:
Enum:
Użycie (gdzie o.OrderType jest właściwością o tej samej nazwie co wyliczenie):
Co daje mi ciąg „Nowa karta” lub „Przeładuj” zamiast rzeczywistej wartości wyliczeniowej NewCard i napełniania.
źródło
Aktualizacja: Odwiedzając tę stronę, 8 lat później, po dłuższym nie dotykaniu C #, wygląda na to, że moja odpowiedź nie jest już najlepszym rozwiązaniem. Naprawdę podoba mi się rozwiązanie konwertera związane z funkcjami atrybutów.
Jeśli to czytasz, sprawdź także inne odpowiedzi.
(wskazówka: są powyżej tego)
Jak większość z was bardzo podobała mi się wybrana odpowiedź Jakuba Šturca , ale też bardzo nie lubię kopiować i wklejać kodu i staram się robić to tak mało, jak potrafię.
Zdecydowałem więc, że chcę klasy EnumBase, z której większość funkcji jest dziedziczona / wbudowana, co pozwala mi skupić się na treści zamiast na zachowaniu.
Główny problem z tym podejściem polega na tym, że chociaż wartości Enum są instancjami bezpiecznymi dla typu, interakcja dotyczy statycznej implementacji typu Enum Class. Więc przy odrobinie magii generycznej myślę, że w końcu udało mi się uzyskać właściwy miks. Mam nadzieję, że ktoś uzna to za tak przydatne, jak ja.
Zacznę od przykładu Jakuba, ale używając dziedziczenia i ogólnych:
A oto klasa podstawowa:
źródło
Zgadzam się z Keithem, ale nie mogę (jeszcze) głosować.
Używam metody statycznej i instrukcji swith, aby zwrócić dokładnie to, czego chcę. W bazie danych przechowuję tinyint, a mój kod wykorzystuje tylko rzeczywiste wyliczanie, więc ciągi znaków odpowiadają wymaganiom interfejsu użytkownika. Po licznych testach spowodowało to najlepszą wydajność i największą kontrolę nad wydajnością.
Jednak według niektórych kont prowadzi to do możliwego koszmaru konserwacji i zapachu kodu. Staram się obserwować wyliczenia, które są długie i dużo wyliczeń, lub te, które często się zmieniają. W przeciwnym razie było to dla mnie świetne rozwiązanie.
źródło
Jeśli przyszedłeś tutaj, aby zaimplementować prosty „Enum”, ale którego wartości to ciągi zamiast ints, oto najprostsze rozwiązanie:
Realizacja:
źródło
static readonly
.Kiedy napotykam ten problem, na kilka pytań staram się znaleźć odpowiedzi w pierwszej kolejności:
Najprostszym sposobem na to jest
Enum.GetValue
(i wsparcie przy użyciu tripping trippingEnum.Parse
). Często warto również zbudowaćTypeConverter
, jak sugeruje Steve Mitcham, obsługę interfejsu użytkownika. (Nie trzeba budowaćTypeConverter
gdy używasz arkuszy własności, co jest jedną z miłych rzeczy w arkuszach własności. Chociaż pan wie, że mają swoje własne problemy).Ogólnie rzecz biorąc, jeśli odpowiedzi na powyższe pytania sugerują, że to nie zadziała, moim następnym krokiem jest stworzenie i wypełnienie pliku statycznego
Dictionary<MyEnum, string>
lub ewentualnieDictionary<Type, Dictionary<int, string>>
. Często pomijam pośredni krok dekorowania kodu z atrybutami, ponieważ to, co zwykle schodzi po szczupaku, to konieczność zmiany przyjaznych wartości po wdrożeniu (często, ale nie zawsze, z powodu lokalizacji).źródło
Chciałem opublikować to jako komentarz do cytowanego poniżej postu, ale nie mogłem, ponieważ nie mam wystarczającej liczby przedstawicieli - więc proszę nie głosować w dół. Kod zawierał błąd i chciałem zwrócić uwagę na osoby próbujące skorzystać z tego rozwiązania:
Powinien być
Brillant!
źródło
Mój wariant
Kod wygląda trochę brzydko, ale zastosowania tej struktury są dość reprezentatywne.
Myślę też, że jeśli wymagane jest wiele takich wyliczeń, można by użyć generowania kodu (np. T4).
źródło
Opcja 1:
i wtedy
Opcja 2:
źródło
Jeśli pomyślisz o problemie, który próbujemy rozwiązać, w ogóle nie potrzebujemy enum. Potrzebujemy obiektu, który pozwala na powiązanie określonej liczby wartości ze sobą; innymi słowy, aby zdefiniować klasę.
Bezpieczny wzór wyliczenia Jakuba Šturca jest najlepszą opcją, jaką tu widzę.
Spójrz na to:
źródło
dla mnie pragmatyczne podejście to klasa wewnątrz klasy, przykład:
źródło
Utworzyłem klasę bazową do tworzenia wyliczeń o wartościach łańcuchowych w .NET. Jest to tylko jeden plik C #, który można skopiować i wkleić do swoich projektów lub zainstalować za pomocą pakietu NuGet o nazwie StringEnum . GitHub Repo
<completitionlist>
. (Działa zarówno w języku C #, jak i VB)Instalacja:
.Net Standard 1.0
więc działa na.Net Core
> = 1.0,.Net Framework
> = 4.5,Mono
> = 4.6 itd.źródło
Oto jeszcze jeden sposób na wykonanie zadania powiązania ciągów z wyliczeniami:
Ta metoda nazywa się tak:
Możesz grupować powiązane wyliczenia w ich własnej strukturze. Ponieważ ta metoda wykorzystuje typ wyliczenia, można użyć Intellisense do wyświetlenia listy wyliczeń podczas tworzenia
GetString()
połączenia.Opcjonalnie możesz użyć nowego operatora w
DATABASE
strukturze. Nieużywanie go oznacza, że łańcuchyList
nie są przydzielane, dopóki nieGetString()
zostanie wykonane pierwsze wywołanie.źródło
Wiele świetnych odpowiedzi tutaj, ale w moim przypadku nie rozwiązałem tego, co chciałem z „enum strun”, czyli:
1,2 i 4 można faktycznie rozwiązać za pomocą C # Typedef ciągu (ponieważ ciągi można przełączać w c #)
3 można rozwiązać za pomocą stałych statycznych. Więc jeśli masz te same potrzeby, jest to najprostsze podejście:
Pozwala to na przykład:
i
Gdzie CreateType można wywołać za pomocą łańcucha lub typu. Jednak wadą jest to, że każdy ciąg znaków jest automatycznie prawidłowym wyliczeniem , można to zmodyfikować, ale wtedy wymagałoby to jakiejś funkcji init ... a może sprawi, że będą one jawnie rzutowane wewnętrznie?
Teraz, jeśli wartość int było dla ciebie ważne (być może dla porównania prędkości), to mogłaby korzystać z niektórych pomysłów z Jakub Šturc fantastycznej odpowiedzi i zrobić coś bit szalony, to moja stab na to:
ale oczywiście „Typ bob = 4;” byłoby bez znaczenia, gdybyś ich nie zainicjował, co w pewnym sensie doprowadziłoby do porażki ...
Ale teoretycznie TypeA == TypeB byłby szybszy ...
źródło
Jeśli rozumiem cię poprawnie, możesz po prostu użyć .ToString (), aby pobrać nazwę wyliczenia z wartości (Zakładając, że jest już rzutowany jako wyliczenie); Jeśli miałeś nagą int (powiedzmy z bazy danych lub czegoś), możesz najpierw rzucić ją na wyliczenie. Obie metody poniżej pozwolą ci uzyskać nazwę enum.
Pamiętaj jednak, że druga technika zakłada, że używasz ints, a twój indeks jest oparty na 1 (a nie na 0). Dla porównania, funkcja GetNames jest również dość ciężka, generujesz całą tablicę za każdym razem, gdy jest wywoływana. Jak widać w pierwszej technice, funkcja .ToString () jest w rzeczywistości wywoływana niejawnie. Oba są już wspomniane w odpowiedziach, staram się tylko wyjaśnić różnice między nimi.
źródło
stary post, ale ...
Odpowiedź na to może być bardzo prosta. Użyj funkcji Enum.ToString ()
Istnieje 6 przeciążeń tej funkcji, możesz użyć Enum.Tostring („F”) lub Enum.ToString (), aby zwrócić wartość ciągu. Nie musisz zawracać sobie głowy niczym innym. Tutaj jest działająca wersja demonstracyjna
Pamiętaj, że to rozwiązanie może nie działać dla wszystkich kompilatorów ( ta wersja demonstracyjna nie działa zgodnie z oczekiwaniami ), ale przynajmniej działa dla najnowszego kompilatora.
źródło
na podstawie MSDN: http://msdn.microsoft.com/en-us/library/cc138362.aspx
str będzie nazwami pól
źródło
Cóż, po przeczytaniu wszystkich powyższych stwierdzeń wydaje mi się, że faceci nadmiernie skomplikowali kwestię przekształcania enumeratorów w łańcuchy. Podobał mi się pomysł posiadania atrybutów nad polami wyliczanymi, ale myślę, że atrybuty są używane głównie do metadanych, ale w twoim przypadku myślę, że wszystko, czego potrzebujesz, to jakaś lokalizacja.
Teraz, jeśli spróbujemy wywołać powyższą metodę, możemy to nazwać w ten sposób
Wszystko, co musisz zrobić, to po prostu utworzyć plik zasobów zawierający wszystkie wartości modułu wyliczającego i odpowiednie ciągi
To, co jest naprawdę bardzo miłe w tym, to to, że będzie bardzo pomocne, jeśli potrzebujesz zlokalizować aplikację, ponieważ wszystko, co musisz zrobić, to po prostu utworzyć inny plik zasobów w nowym języku! i Voe-la!
źródło
Kiedy jestem w takiej sytuacji, proponuję poniższe rozwiązanie.
I jako klasa konsumująca, którą możesz mieć
I przy użyciu słownika dwukierunkowego: Na podstawie tego ( https://stackoverflow.com/a/255638/986160 ) przy założeniu, że klucze zostaną powiązane z pojedynczymi wartościami w słowniku i podobnym do ( https://stackoverflow.com/a / 255630/986160 ), ale nieco bardziej elegancki. Słownik ten jest również wymienny i możesz przechodzić od ints do string. Poza tym nie musisz mieć żadnych ciągów znaków w bazie kodu, z wyjątkiem tej klasy.
źródło
W przypadku większych zestawów enum struny wymienione przykłady mogą stać się męczące. Jeśli potrzebujesz listy kodów statusu lub listy innych wyliczeń opartych na ciągach znaków, irytujący jest system atrybutów, a konfiguracja ma postać statyczną z instancjami samego siebie. W moim własnym rozwiązaniu korzystam z szablonów T4, aby łatwiej było uzyskać wyliczenia oparte na łańcuchach. Wynik jest podobny do działania klasy HttpMethod.
Możesz użyć tego w następujący sposób:
Zaczynasz od pliku Enum.tt.
Następnie dodajesz plik StringEnum.ttinclude.
Na koniec rekompilujesz plik Enum.tt, a dane wyjściowe wyglądają następująco:
źródło