Перетворити Enum в String


163

Який найкращий спосіб перетворити Enum у String в .NET 3.5?

  • Enum.GetName
  • Enum.Format
  • ToString

Чому я віддаю перевагу одному з таких перед іншими? Чи працює краще?


10
Я шукав і не зміг знайти дублікат. Якщо ви можете надати посилання, я видалю це питання.
Ерік Вайнау

1
Іноді використання заяви перемикання - не найкраща практика (коли у вас великі перерахунки) ви можете використовувати Dict <> замість цього
Хлопець L

1
Якщо ви хочете досягти кращої продуктивності, ви можете використовувати клас, описаний у цій статті codeproject.com/KB/dotnet/enum.aspx . Використання виглядатиме так Enum <YourEnum> .ToString (yourValue) або Enum <YourEnum> .ToString ((int) yourValue)
ideafixxxer

5
Кодування, щоб не порушити крапку, є втіленням хвоста, що висить собакою. SW виробники не замислюються: "Давайте зробимо чудовий додаток, щоб dotfuscator мав щось робити". Dofuscator існує для сприяння розвитку SW. Якщо він не може цього зробити ... може!
micahhoover

Відповіді:


126

Станом на C # 6 найкращим способом отримати ім’я перерахунку є новий nameofоператор:

nameof(MyEnum.EnumValue);

// Ouputs
> "EnumValue"

Це працює під час компіляції, при цьому enum замінюється рядком у компільованому результаті, а це означає, що це найшвидший спосіб.

Будь-яке використання імен перерахувань перешкоджає обтурації коду, якщо ви вважаєте, що обтурація імен enum є вагомим чи важливим - це, мабуть, зовсім інше питання.


11
Це заслуговує більшої уваги. Очевидне обмеження, незважаючи на те, що є вимогою до введення часу компіляції. На мою думку, цьому слід віддавати перевагу, коли це можливо . "Перейменувати" та "знайти всі посилання" враховуйте це, потенційно уникаючи магічних рядків та дублюючих констант.
Тимо

1
Отже, я думаю, це не буде працювати, коли значення enum визначається під час виконання? Наприклад: MyEnum зміннийEnum; variaEnum = setEnumValueMethod (); nameof (зміннийEnum);
Макстер

1
@Maxter ні, як nameof(variableEnum)буде "variableEnum". Він відображає (під час побудови) назву поля / властивості / парам / змінної, а не значення .
Кіт

ви на жаль, не працює, якщо це зробити: var someEnumvalue = SomeEnum.FooBar; nameof (деякийEnumvalue);
Підозріло

1
@ Мабуть, так, це повернеться "someEnumValue", тоді як вам потрібно nameof(SomeEnum.FooBar)буде отримати "FooBar".
Кіт

93

Працює над нашим проектом ...

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);
}

7
Enum.GetName приймає значення як об'єктний аргумент. Це означає, що значення буде впаковане, і це витратить ресурси процесора на розподіл та збирання сміття. Якщо це робиться багато часу, Enum.GetName матиме набагато меншу пропускну здатність, ніж кешування значень у словнику та пошук там імені.
Побіг

@ Ran, що таке рішення, яке використовувати замість цього?
shaijut

Це повинно бути відповідь
Squibly

робить мій проект повільніше. toString () швидше.
d2k2

29

На моїх тестах, Enum.GetNameбуло швидше і з пристойним запасом. Внутрішні ToStringдзвінки Enum.GetName. З джерела для .NET 4.0, основні елементи:

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);
    }
}

Не можу сказати, що це причина точно, але стан тестів один швидше, ніж інший. Обидва дзвінки включають бокс (насправді вони є дзеркальними дзвінками, ви по суті отримуєте назви полів) і можуть бути повільними на ваш смак.

Налаштування тесту : перерахунок з 8 значеннями, немає. ітерацій = 1000000

Результат : Enum.GetName => 700 мс, ToString => 2000 мс

Якщо швидкість не помітна, я б не переймався та використовував, ToStringоскільки вона пропонує набагато чистіший дзвінок. Контрастність

Enum.GetName(typeof(Bla), value)

з

value.ToString()

25

Enum.GetName (...)

Це найелегантніший метод, який призначений саме для цього.

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

Хоча я не бачу проблем із викликом, .ToString()оскільки він просто коротший.

var enumValueString = MyEnum.MyValue.ToString();

З новим синтаксисом C # 6 ви можете використовувати:

nameof(MyEnum.MyValue)

20

Все це внутрішньо закінчує викликати метод, який називається InternalGetValueAsString. Різниця між ToStringі GetNameполягає в тому, що слід GetNameспочатку перевірити кілька речей:

  1. Введений тип не є нульовим.
  2. Тип, який ви ввели, насправді є перерахуванням.
  3. Значення, яке ви передали, не є нульовим.
  4. Значення, яке ви передали, має тип, який перелічення може фактично використовувати як базовий тип, або тип самого перерахування. Він використовує GetTypeзначення, щоб перевірити це.

.ToStringне потрібно турбуватися про будь-який із цих вищезазначених питань, оскільки він викликається в екземплярі самого класу, а не у переданому у версії, тому через те, що у .ToStringметоду немає однакових проблем перевірки Як статичні методи я б зробив висновок, що .ToStringце найшвидший спосіб отримати значення у вигляді рядка.


2
де ти це перевірив? Якою була версія складання? Я отримую дуже різні результати.
nawfal

17

Найкраще, що я можу знайти, це непов'язане запитання про MSDN , яке містить фрагмент XML, який відповідає на це питання. Будь-який із цих методів має той самий недолік: вони викликають enum.toString(), що не працює належним чином при використанні Dotfuscation . Здається, інші побоювання стосуються непрямого боксу (GetName і Format). На жаль, я не можу знайти жодних причин ефективності використання будь-якого з перерахованого вище.

Перефразовуючи фрагмент xml ,

Передача кодованого перерахунку до string.Format () або будь-яка інша функція може призвести до виклику enum.ToString(). Це спричинить проблеми при дотфускуванні. Ви не повинні використовувати enum.ToString(), enum.GetNames(), enum.GetName(), enum.Format()або enum.Parse()перетворити перерахування в рядок. Натомість використовуйте оператор перемикання, а також, якщо потрібно, інтернаціоналізуйте імена.


16

Enum.GetName()

Format()насправді просто обгортка GetName()з деяким функціонуванням форматування (або InternalGetValueAsString()якщо бути точним). ToString()майже все те саме, що Format(). Я думаю GetName(), що найкращий варіант, оскільки абсолютно очевидно, що це робить для тих, хто читає джерело.


8

Я створюю метод розширення "Опис" і прикріплюю його до перерахунку, щоб я міг отримати справді зручну назву, яка включає пробіли та корпуси. Мені ніколи не подобалося використовувати саме значення enum як відображуваний текст, тому що це те, що ми розробники використовують для створення більш читабельного коду. Він не призначений для відображення інтерфейсу користувача. Я хочу мати змогу змінити інтерфейс користувача, не переходячи і не змінюючи переліків.


6

Я не знаю, що таке "кращий" метод (запитайте 100 людей і отримайте 100 різних думок), але робити те, що найпростіше і що працює. GetNameпрацює, але вимагає набагато більше натискань клавіш. ToString()здається, що цю роботу виконали дуже добре.


1

Для прихильників VB:

EnumStringValue = System.Enum.GetName(GetType(MyEnum), MyEnumValue)

0

Це теж би спрацювало.

    List<string> names = Enum.GetNames(typeof(MyEnum)).ToList();

0

ToString()дає найбільш очевидний результат з точки зору читабельності при використанніEnum.GetName() вимагає трохи більше розумового розбору, щоб швидко зрозуміти, що його намагаються робити (якщо ви не бачите шаблон завжди).

З чистої точки зору продуктивності, як це вже було передбачено у відповіді @ nawfal, Enum.GetName()краще.

Якщо продуктивність дійсно ваша ціль, було б ще краще заздалегідь передбачити огляд (за допомогою словника чи іншого відображення).

У C ++ / CLI це виглядатиме так

Dictionary<String^, MyEnum> mapping;
for each (MyEnum field in Enum::GetValues(MyEnum::typeid))
{
    mapping.Add(Enum::GetName(MyEnum::typeid), field);
}

Порівняння за допомогою перерахунку 100 елементів та 1000000 повторень:

Enum.GetName: ~
800ms .ToString (): ~ 1600ms Зіставлення
словника: ~ 250ms


-3

Просте: перерахування імен до списку:

List<String> NameList = Enum.GetNames(typeof(YourEnumName)).Cast<string>().ToList()

Привіт @Brian, я не думаю, що вам потрібно передавати вихід GetNames ()
Nic
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.