Konwertuj Enum na ciąg

163

Jaki jest preferowany sposób konwersji wyliczenia na ciąg znaków w .NET 3.5?

  • Enum.GetName
  • Enum.Format
  • ToString

Dlaczego powinienem preferować jeden z nich od innych? Czy ktoś działa lepiej?

Eric Weilnau
źródło
10
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.

Keith
źródło
11
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".
Keith
93

Pracuje dla naszego projektu ...

public static String convertToString(this Enum eff)
{
    return Enum.GetName(eff.GetType(), eff);
}

public static EnumType converToEnum<EnumType>(this String enumValue)  
{
    return (EnumType) Enum.Parse(typeof(EnumType), enumValue);
}
Sumtraveller
źródło
7
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:

public override String ToString()
{
     return Enum.InternalFormat((RuntimeType)GetType(), GetValue());
}

private static String InternalFormat(RuntimeType eT, Object value)
{
    if (!eT.IsDefined(typeof(System.FlagsAttribute), false))
    {
        String retval = GetName(eT, value); //<== the one
        if (retval == null)
            return value.ToString();
        else
            return retval;
    }
    else
    {
        return InternalFlagsFormat(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

Enum.GetName(typeof(Bla), value)

z

value.ToString()
nawfal
źródło
25

Enum.GetName (...)

To najbardziej elegancka metoda, która jest do tego przeznaczona.

var enumValueString = Enum.GetName(typeof (MyEnum), MyEnum.MyValue);

Chociaż nie widzę żadnych problemów z dzwonieniem, .ToString()ponieważ jest po prostu krótszy.

var enumValueString = MyEnum.MyValue.ToString();

Dzięki nowej składni C # 6 możesz użyć:

nameof(MyEnum.MyValue)
Andrei
źródło
20

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:

  1. Podany typ nie jest pusty.
  2. Wprowadzony typ jest w rzeczywistości wyliczeniem.
  3. Wartość, którą przekazałeś, nie jest zerowa.
  4. 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.

David Morton
źródło
2
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.

Parafrazowanie z fragmentu xml ,

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.

jpaugh
źródło
16

Enum.GetName()

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.

Tamas Czinege
źródło
8

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.

Tańce z bambusem
źródło
6

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.

Perry Neal
źródło
1

Dla miłośników VB:

EnumStringValue = System.Enum.GetName(GetType(MyEnum), MyEnumValue)
GlennG
źródło
0

To też by działało.

    List<string> names = Enum.GetNames(typeof(MyEnum)).ToList();
Nic
źródło
0

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:

Enum.GetName: ~ 800ms
.ToString (): ~ 1600ms
Mapowanie słownika: ~ 250ms

John Go-Soco
źródło
-3

Proste: nazwy wyliczeń w liście:

List<String> NameList = Enum.GetNames(typeof(YourEnumName)).Cast<string>().ToList()
Brian
źródło
Cześć @Brian, nie sądzę, abyś musiał przesyłać dane wyjściowe GetNames ()
Nic