Конвертировать Enum в String

163

Какой предпочтительный способ преобразовать Enum в строку в .NET 3.5?

  • Enum.GetName
  • Enum.Format
  • Нанизывать

Почему я должен предпочесть один из них другим? Работает ли лучше?

Эрик Вейльну
источник
10
Я искал и не смог найти дубликат. Если вы можете предоставить ссылку, я удалю этот вопрос.
Эрик Вейльну
1
иногда использование оператора switch не является наилучшей практикой (когда у вас большие перечисления), вместо этого вы можете использовать Dict <>
Guy L
1
Если вы хотите повысить производительность, вы можете использовать класс, описанный в этой статье codeproject.com/KB/dotnet/enum.aspx . Использование будет выглядеть следующим образом: Enum <YourEnum> .ToString (yourValue) или Enum <YourEnum> .ToString ((int) yourValue)
ideafixxxer
5
Кодирование, чтобы не сломать точечную дефекацию, является воплощением хвоста, виляющего собакой. Производители ПО не думают: «Давайте сделаем отличное приложение, чтобы у dotfuscator было чем заняться». Dofuscator существует, чтобы помочь облегчить развитие SW. Если это не может сделать это ... может это!
micahhoover

Ответы:

127

Начиная с C # 6, лучший способ получить имя перечисления - это новый nameofоператор:

nameof(MyEnum.EnumValue);

// Ouputs
> "EnumValue"

Это работает во время компиляции, при этом перечисление заменяется строкой в ​​скомпилированном результате, что, в свою очередь, означает, что это самый быстрый возможный способ.

Любое использование имен enum мешает запутыванию кода, если вы считаете, что запутывание имен enum стоит или важно - это, вероятно, совсем другой вопрос.

Кит
источник
11
Это заслуживает большего внимания. Несмотря на очевидное ограничение, то есть требование ввода во время компиляции. На мой взгляд, это должно быть предпочтительным, когда это возможно . «Переименовать» и «найти все ссылки» также учитывают это, потенциально избегая магических строк и дублирующих констант.
Тимо
1
Так что я думаю, что это не сработает, если значение enum определено во время выполнения? Пример: MyEnum variableEnum; variableEnum = setEnumValueMethod (); nameof (variableEnum);
Maxter
1
@ Макстер нет, как nameof(variableEnum)будет "variableEnum". Он отражает (во время сборки) имя поля / свойства / параметра / переменной, а не значение .
Кит
вы. к сожалению, не работает, если вы делаете это: var someEnumvalue = SomeEnum.FooBar; nameof (someEnumvalue);
Жалко
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);
}
Sumtraveller
источник
7
Enum.GetName принимает значение в качестве аргумента объекта. Это означает, что значение будет упаковано, и это будет тратить ресурсы ЦП на распределение и сборку мусора. Если это выполняется много времени, Enum.GetName будет иметь гораздо меньшую пропускную способность, чем кэширование значений в словаре и поиск имени в нем.
Бежал
@Ran, так что такое решение, которое вместо этого использовать?
Shaijut
Это должен быть ответ
Squbly
делает мой проект медленнее. 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()преобразовать перечисление в строку. Вместо этого используйте оператор switch, а также при необходимости интернационализируйте имена.

jpaugh
источник
16

Enum.GetName()

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

Тамас Чинеге
источник
8

Я создаю метод расширения «Description» и присоединяю его к перечислению, чтобы получить действительно удобное для пользователя наименование, включающее пробелы и регистр. Мне никогда не нравилось использовать само значение enum в качестве отображаемого текста, потому что это то, что мы разработчики используем для создания более читабельного кода. Он не предназначен для отображения пользовательского интерфейса. Я хочу иметь возможность изменять пользовательский интерфейс, не проходя и не меняя перечисления во всем.

DancesWithBamboo
источник
6

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

Перри Нил
источник
1

Для поклонников VB:

EnumStringValue = System.Enum.GetName(GetType(MyEnum), MyEnumValue)
GlennG
источник
0

Это тоже сработало бы.

    List<string> names = Enum.GetNames(typeof(MyEnum)).ToList();
Nic
источник
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