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?
Jaki jest preferowany sposób konwersji wyliczenia na ciąg znaków w .NET 3.5?
Dlaczego powinienem preferować jeden z nich od innych? Czy ktoś działa lepiej?
Odpowiedzi:
Od C # 6 najlepszym sposobem uzyskania nazwy wyliczenia jest nowy nameof
operator:
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.
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 ...
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);
}
W moich testach Enum.GetName
był szybszy i przyzwoity. ToString
Połą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, ToString
ponieważ oferuje znacznie czystsze połączenie. Kontrast
Enum.GetName(typeof(Bla), value)
z
value.ToString()
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)
Wszystko to wewnętrznie kończy się wywołaniem metody o nazwie InternalGetValueAsString
. Różnica między ToString
i GetName
byłaby taka, że GetName
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.
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()
lubenum.Parse()
przekonwertować enum na ciąg. Zamiast tego użyj instrukcji switch, a jeśli to konieczne, dokonaj internacjonalizacji nazw.
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.
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. GetName
dział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:
Enum.GetName: ~ 800ms
.ToString (): ~ 1600ms
Mapowanie słownika: ~ 250ms