Szukałem i nie mogłem znaleźć duplikatu. Jeśli możesz podać link, usunę to pytanie.
Eric Weilnau
1
czasami użycie instrukcji switch nie jest najlepszą praktyką (gdy masz duże wyliczenia), możesz zamiast tego użyć Dict <>
Guy L
1
Jeśli chcesz uzyskać lepszą wydajność, możesz użyć klasy opisanej w tym artykule codeproject.com/KB/dotnet/enum.aspx . Sposób użycia będzie wyglądał następująco: Enum <YourEnum> .ToString (yourValue) lub Enum <YourEnum> .ToString ((int) yourValue)
ideafixxxer
5
Kodowanie, aby nie przerywać dotfuskacji, jest uosobieniem machania psem ogonem. Producenci SW nie myślą: „Zróbmy świetną aplikację, aby dotfuscator miał coś do zrobienia”. Dofuscator istnieje, aby ułatwić rozwój oprogramowania SW. Jeśli nie może tego zrobić ... prawda!
micahhoover
Odpowiedzi:
126
Od C # 6 najlepszym sposobem uzyskania nazwy wyliczenia jest nowy nameofoperator:
nameof(MyEnum.EnumValue);// Ouputs>"EnumValue"
Działa to w czasie kompilacji, gdzie wyliczenie jest zastępowane ciągiem znaków w skompilowanym wyniku, co z kolei oznacza, że jest to najszybszy możliwy sposób.
Każde użycie nazw wyliczeń koliduje z zaciemnianiem kodu, jeśli uważasz, że zaciemnianie nazw wyliczeń jest warte zachodu lub ważne - to prawdopodobnie zupełnie inna kwestia.
To zasługuje na więcej uwagi. Bez względu na oczywiste ograniczenie, tj. Wymóg wprowadzania danych w czasie kompilacji. Moim zdaniem powinno to być preferowane, gdy tylko jest to możliwe . „Zmień nazwę” i „znajdź wszystkie odniesienia” również biorą to pod uwagę, potencjalnie unikając magicznych ciągów i duplikatów stałych.
Timo
1
Więc myślę, że to nie zadziała, gdy wartość wyliczenia jest zdefiniowana w czasie wykonywania? Np .: MyEnum variableEnum; variableEnum = setEnumValueMethod (); nameof (zmiennaEnum);
Maxter
1
@Maxter nie, jak nameof(variableEnum)będzie "variableEnum". Odzwierciedla (w czasie kompilacji) nazwę pola / właściwości / parametru / zmiennej, a nie wartość .
Keith
człek. niestety nie działa, jeśli to zrobisz: var someEnumvalue = SomeEnum.FooBar; nameof (someEnumvalue);
Kwadratowy
1
@ Najwyraźniej tak, to wróci "someEnumValue", podczas gdy będziesz musiał nameof(SomeEnum.FooBar)dostać "FooBar".
Enum.GetName przyjmuje wartość jako argument obiektu. Oznacza to, że wartość zostanie umieszczona w ramce, co spowoduje marnowanie zasobów procesora na alokację i wyrzucanie elementów bezużytecznych. Jeśli jest to robione dużo czasu, Enum.GetName będzie miało znacznie mniejszą przepustowość niż buforowanie wartości w słowniku i szukanie tam nazwy.
Biegał
@Ran więc jakie jest rozwiązanie, którego użyć zamiast tego?
shaijut
To powinna być odpowiedź
Squbly
spowalnia mój projekt. toString () jest szybsze.
d2k2
29
W moich testach Enum.GetNamebył szybszy i przyzwoity. ToStringPołączenia wewnętrzne Enum.GetName. Ze źródła .NET 4.0, podstawowe informacje:
publicoverrideStringToString(){returnEnum.InternalFormat((RuntimeType)GetType(),GetValue());}privatestaticStringInternalFormat(RuntimeType eT,Objectvalue){if(!eT.IsDefined(typeof(System.FlagsAttribute),false)){String retval =GetName(eT,value);//<== the oneif(retval ==null)returnvalue.ToString();elsereturn retval;}else{returnInternalFlagsFormat(eT,value);}}
Nie mogę powiedzieć, żeby to był powód na pewno, ale testy pokazują, że jeden jest szybszy od drugiego. Oba wezwania dotyczą boksu (w rzeczywistości są to wywołania odbicia, zasadniczo pobierasz nazwy pól) i mogą być powolne według własnego uznania.
Konfiguracja testu : wyliczenie z 8 wartościami, nie. iteracji = 1000000
Wynik : Enum.GetName => 700 ms, ToString => 2000 ms
Jeśli prędkość nie jest zauważalna, nie przejmowałbym się i nie używałbym, ToStringponieważ oferuje znacznie czystsze połączenie. Kontrast
Wszystko to wewnętrznie kończy się wywołaniem metody o nazwie InternalGetValueAsString. Różnica między ToStringi GetNamebyłaby taka, że GetNamenajpierw trzeba zweryfikować kilka rzeczy:
Podany typ nie jest pusty.
Wprowadzony typ jest w rzeczywistości wyliczeniem.
Wartość, którą przekazałeś, nie jest zerowa.
Wartość, którą przekazałeś, jest typu, którego wyliczenie może faktycznie używać jako typu podstawowego lub typu samego wyliczenia. Używa GetTypewartości, aby to sprawdzić.
.ToStringnie musi się martwić żadną z powyższych kwestii, ponieważ jest wywoływana na instancji samej klasy, a nie na przekazanej wersji, dlatego ze względu na fakt, że .ToStringmetoda nie ma takich samych problemów z weryfikacją jako metody statyczne doszedłbym do wniosku, że .ToStringjest to najszybszy sposób uzyskania wartości jako ciągu znaków.
gdzie to sprawdziłeś? Jaka była wersja zespołu? Otrzymuję bardzo różne wyniki.
nawfal
17
Najlepsze, co mogę znaleźć, to to niezwiązane pytanie w witrynie MSDN , które zawiera fragment kodu XML odpowiadający na to pytanie. Każda z tych metod ma tę samą wadę: wywołują enum.toString(), co nie działa poprawnie podczas korzystania z Dotfuscation . Wydaje się, że inne obawy dotyczą boksu pośredniego (GetName i Format). Niestety, nie mogę znaleźć żadnych powodów wydajnościowych dla używania któregokolwiek z powyższych.
Przekazanie wyliczenia w ramce do string.Format () lub dowolnej innej funkcji może spowodować enum.ToString()wywołanie. Spowoduje to problemy podczas Dotfuscating. Nie należy stosować enum.ToString(), enum.GetNames(), enum.GetName(), enum.Format()lub enum.Parse()przekonwertować enum na ciąg. Zamiast tego użyj instrukcji switch, a jeśli to konieczne, dokonaj internacjonalizacji nazw.
Format()to tak naprawdę tylko opakowanie GetName()z pewnymi funkcjami formatowania (a InternalGetValueAsString()dokładniej). ToString()jest prawie taki sam jak Format(). Myślę, że GetName()to najlepsza opcja, ponieważ jest całkowicie oczywiste, co robi dla każdego, kto czyta źródło.
Tworzę metodę rozszerzenia „Opis” i dołączam ją do wyliczenia, aby uzyskać naprawdę przyjazne dla użytkownika nazewnictwo, które zawiera spacje i wielkość liter. Nigdy nie podobało mi się używanie samej wartości wyliczenia jako wyświetlanego tekstu, ponieważ jest to coś, czego my programiści używamy do tworzenia bardziej czytelnego kodu. Nie jest przeznaczony do wyświetlania interfejsu użytkownika. Chcę mieć możliwość zmiany interfejsu użytkownika bez przechodzenia przez wszystkie wyliczenia i zmieniania ich.
Nie wiem, jaka jest „preferowana” metoda (zapytaj 100 osób i zbierz 100 różnych opinii), ale rób to, co jest najprostsze i co działa. GetNamedziała, ale wymaga znacznie więcej naciśnięć klawiszy. ToString()wydaje się, że wykonuje swoją pracę bardzo dobrze.
ToString()daje najbardziej oczywisty wynik z punktu widzenia czytelności podczas używaniaEnum.GetName() wymaga nieco więcej analizy mentalnej, aby szybko zrozumieć, co próbuje zrobić (chyba że cały czas widzisz wzór).
Z czystego punktu widzenia wydajności, jak już podano w odpowiedzi @ nawfal, Enum.GetName()jest lepsze.
Jeśli jednak naprawdę zależy Ci na wydajności, jeszcze lepiej byłoby wcześniej przeprowadzić wyszukiwanie (używając słownika lub innego mapowania).
W C ++ / CLI wyglądałoby to tak
Dictionary<String^,MyEnum> mapping;for each (MyEnum field in Enum::GetValues(MyEnum::typeid)){
mapping.Add(Enum::GetName(MyEnum::typeid), field);}
Porównanie przy użyciu wyliczenia 100 elementów i 1000000 iteracji:
Odpowiedzi:
Od C # 6 najlepszym sposobem uzyskania nazwy wyliczenia jest nowy
nameof
operator:Działa to w czasie kompilacji, gdzie wyliczenie jest zastępowane ciągiem znaków w skompilowanym wyniku, co z kolei oznacza, że jest to najszybszy możliwy sposób.
Każde użycie nazw wyliczeń koliduje z zaciemnianiem kodu, jeśli uważasz, że zaciemnianie nazw wyliczeń jest warte zachodu lub ważne - to prawdopodobnie zupełnie inna kwestia.
źródło
nameof(variableEnum)
będzie"variableEnum"
. Odzwierciedla (w czasie kompilacji) nazwę pola / właściwości / parametru / zmiennej, a nie wartość ."someEnumValue"
, podczas gdy będziesz musiałnameof(SomeEnum.FooBar)
dostać"FooBar"
.Pracuje dla naszego projektu ...
źródło
W moich testach
Enum.GetName
był szybszy i przyzwoity.ToString
Połączenia wewnętrzneEnum.GetName
. Ze źródła .NET 4.0, podstawowe informacje:Nie mogę powiedzieć, żeby to był powód na pewno, ale testy pokazują, że jeden jest szybszy od drugiego. Oba wezwania dotyczą boksu (w rzeczywistości są to wywołania odbicia, zasadniczo pobierasz nazwy pól) i mogą być powolne według własnego uznania.
Jeśli prędkość nie jest zauważalna, nie przejmowałbym się i nie używałbym,
ToString
ponieważ oferuje znacznie czystsze połączenie. Kontrastz
źródło
Enum.GetName (...)
To najbardziej elegancka metoda, która jest do tego przeznaczona.
Chociaż nie widzę żadnych problemów z dzwonieniem,
.ToString()
ponieważ jest po prostu krótszy.Dzięki nowej składni C # 6 możesz użyć:
źródło
Wszystko to wewnętrznie kończy się wywołaniem metody o nazwie
InternalGetValueAsString
. Różnica międzyToString
iGetName
byłaby taka, żeGetName
najpierw trzeba zweryfikować kilka rzeczy:GetType
wartości, aby to sprawdzić..ToString
nie musi się martwić żadną z powyższych kwestii, ponieważ jest wywoływana na instancji samej klasy, a nie na przekazanej wersji, dlatego ze względu na fakt, że.ToString
metoda nie ma takich samych problemów z weryfikacją jako metody statyczne doszedłbym do wniosku, że.ToString
jest to najszybszy sposób uzyskania wartości jako ciągu znaków.źródło
Najlepsze, co mogę znaleźć, to to niezwiązane pytanie w witrynie MSDN , które zawiera fragment kodu XML odpowiadający na to pytanie. Każda z tych metod ma tę samą wadę: wywołują
enum.toString()
, co nie działa poprawnie podczas korzystania z Dotfuscation . Wydaje się, że inne obawy dotyczą boksu pośredniego (GetName i Format). Niestety, nie mogę znaleźć żadnych powodów wydajnościowych dla używania któregokolwiek z powyższych.Parafrazowanie z fragmentu xml ,
źródło
Enum.GetName()
Format()
to tak naprawdę tylko opakowanieGetName()
z pewnymi funkcjami formatowania (aInternalGetValueAsString()
dokładniej).ToString()
jest prawie taki sam jakFormat()
. Myślę, żeGetName()
to najlepsza opcja, ponieważ jest całkowicie oczywiste, co robi dla każdego, kto czyta źródło.źródło
Tworzę metodę rozszerzenia „Opis” i dołączam ją do wyliczenia, aby uzyskać naprawdę przyjazne dla użytkownika nazewnictwo, które zawiera spacje i wielkość liter. Nigdy nie podobało mi się używanie samej wartości wyliczenia jako wyświetlanego tekstu, ponieważ jest to coś, czego my programiści używamy do tworzenia bardziej czytelnego kodu. Nie jest przeznaczony do wyświetlania interfejsu użytkownika. Chcę mieć możliwość zmiany interfejsu użytkownika bez przechodzenia przez wszystkie wyliczenia i zmieniania ich.
źródło
Nie wiem, jaka jest „preferowana” metoda (zapytaj 100 osób i zbierz 100 różnych opinii), ale rób to, co jest najprostsze i co działa.
GetName
działa, ale wymaga znacznie więcej naciśnięć klawiszy.ToString()
wydaje się, że wykonuje swoją pracę bardzo dobrze.źródło
Dla miłośników VB:
źródło
To też by działało.
źródło
ToString()
daje najbardziej oczywisty wynik z punktu widzenia czytelności podczas używaniaEnum.GetName()
wymaga nieco więcej analizy mentalnej, aby szybko zrozumieć, co próbuje zrobić (chyba że cały czas widzisz wzór).Z czystego punktu widzenia wydajności, jak już podano w odpowiedzi @ nawfal,
Enum.GetName()
jest lepsze.Jeśli jednak naprawdę zależy Ci na wydajności, jeszcze lepiej byłoby wcześniej przeprowadzić wyszukiwanie (używając słownika lub innego mapowania).
W C ++ / CLI wyglądałoby to tak
Porównanie przy użyciu wyliczenia 100 elementów i 1000000 iteracji:
źródło
Proste: nazwy wyliczeń w liście:
źródło