Какой лучший способ конвертировать enum в string? - PullRequest
8 голосов
/ 01 апреля 2010

У меня есть перечисление вот так:

public enum ObectTypes
{
    TypeOne,
    TypeTwo,
    TypeThree,
    ...
    TypeTwenty
 }

тогда мне нужно преобразовать это перечисление в строку. Теперь я делаю так:

public string ConvertToCustomTypeName(ObjectTypes typeObj)
{
    string result = string.Empty;
    switch (typeObj)
    {
        case ObjectTypes.TypeOne: result = "This is type T123"; break;
        case ObjectTypes.TypeTwo: result = "Oh man! This is type T234"; break;
        ...
        case ObjectTypes.TypeTwenty: result = "This is type last"; break;
    }

    return result;
}

Я совершенно уверен, что есть лучший способ сделать это, я ищу какое-то хорошее решение для практики.

РЕДАКТИРОВАТЬ : В строке результата нет ни одного шаблона.

Заранее спасибо.

Ответы [ 10 ]

19 голосов
/ 01 апреля 2010

Я использую атрибут [Description] от System.ComponentModel

Пример:

public enum RoleType
{
    [Description("Allows access to public information")] Guest = 0,
    [Description("Allows access to the blog")] BlogReader = 4,
}

Тогда читать из него я делаю

public static string ReadDescription<T>(T enumMember)
{
    var type = typeof (T);

    var fi = type.GetField(enumMember.ToString());
    var attributes = (DescriptionAttribute[]) 
            fi.GetCustomAttributes(typeof (DescriptionAttribute), false);
    return attributes.Length > 0 ? 
        attributes[0].Description : 
        enumMember.ToString();
}

Тогда использование

ReadDescription(RoleType.Guest);

Примечание: это решение предполагает использование одной культуры, поскольку о нескольких культурах ничего специально не спрашивали. Если вы находитесь в ситуации, когда вам нужно работать с несколькими культурами, я бы использовал DescriptionAttribute или аналогичный для хранения ключа к файлу ресурсов, учитывающему культуру. Хотя вы можете хранить член enum непосредственно в файле .resx, что создаст максимально тесную связь. Я не вижу причин, почему вы хотели бы связать внутреннюю работу вашего приложения (имена членов enum) с ключевыми значениями, которые существуют для целей интернационализации.

9 голосов
/ 01 апреля 2010

Если вам нужна пользовательская строка, лучшим вариантом будет сделать Dictionary< ObjectTypes, string> и просто выполнить поиск по словарю.

Если у вас все в порядке с функцией ToString () по умолчанию, просто используйте typeObj.ToString();

Для словарного подхода вы можете сделать:

private static Dictionary<ObjectTypes, string> enumLookup;

static MyClass()
{
    enumLookup = new Dictionary<ObjectTypes, string>();
    enumLookup.Add(ObjectTypes.TypeOne, "This is type T123");
    enumLookup.Add(ObjectTypes.TypeTwo, "This is type T234");
    // enumLookup.Add...

}

Ваш метод становится:

public string ConvertToCustomTypeName(ObjectTypes typeObj)
{
     // Shouldn't need TryGetValue, unless you're expecting people to mess  with your enum values...
     return enumLookup[typeObj];
}
4 голосов
/ 01 апреля 2010

Используйте предложенный способ ресурсов:

string GetName(Enum e) {
     return Properties.Resources.ResourcesManager.GetString("_enum_"+e.GetType().ToString().Replace('.','_'));
}

Обработка ошибок немного больше ..

2 голосов
/ 01 апреля 2010

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

internal static string MapToName(ObjectTypes value) {
  switch (value) { 
    case ObjectTypes.TypeOne: return "T123";
    case ObjectTypes.TypeTwo: return "T234";
    ...
  }
}

public string ConvertToCustomTypeName(ObjectTypes value) {
  return String.Format("This is type {0}", MapToName(value));
}
1 голос
/ 18 января 2011

Я бы положил эти значения в базу данных. Роли обычно принадлежат базе данных по нескольким причинам, включая следующие:

  1. Отчеты, возможно, должны выполняться для ролей, поэтому необходимо отображать описания.
  2. Определения ролей можно настроить без развертывания нового кода.
  3. Роли должны выполняться с ключевым ограничением.

Если все сделано правильно, производительность не должна быть проблемой при получении ролей из базы данных. Кроме того, поскольку таблица определения роли редко изменяется, она является очень хорошим кандидатом для кэширования.

Если вам нужно взломать Enum, чтобы заставить его работать, возможно, вам не следует использовать Enum. При правильном размещении все должно идти намного лучше в коде с небольшим количеством хаков или вообще без них. Предоставленные Enums имеют свое место; например, довольно статичный взаимоисключающий статус.

1 голос
/ 01 апреля 2010

Не могу в это поверить ... почему никто не предложил файл ресурсов?

Отображение значений перечисления в строки в скомпилированном коде хорошо подходит для быстрого взлома, но в долгосрочной перспективе это плохая практика и затрудняет реорганизацию кода. Что если вы добавите (или вычтете) значение из перечисления? Если вы используете строки из файла ресурсов, все, что вам нужно сделать, это добавить (или удалить) одну запись.

1 голос
/ 01 апреля 2010

Если вы просто хотите использовать имя enum (т.е. TypeOne), вы можете просто вызвать ToString () для самого перечисления

typeObj.ToString()

Если вы хотите пользовательскую строку, основанную на типе, у вас есть несколько различных опций. Оператор switch у вас в порядке, но его поддержание станет беспорядочным, если у вас большое количество перечислений. Или вы можете установить словарь, используя тип enum в качестве ключа и строку в качестве значения.

public enum ObectTypes
{
   One,
   Two
}

Dictionary<ObectTypes, String> myDic = new Dictionary<ObectTypes, string>();
myDic.Add( ObectTypes.One, "Something here for One" );
myDic.Add( ObectTypes.Two, "Something here for Two" );
1 голос
/ 01 апреля 2010

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

0 голосов
/ 18 января 2011

То, что вы уже использовали, не является плохим паттерном. Почти у каждого другого варианта есть свои проблемы. Если бы вы использовали F # для этого типа, вы могли бы сделать что-то вроде:

type ObjectTypes =
| TypeOne
| TypeTwo
| TypeThree
...
| TypeTwenty
with override this.ToString() =
    match this with
    | TypeOne -> "This is type T123"
    | TypeTwo -> "Oh man! This is type T234"
    ...
    | TypeTwenty -> "This is type last"
    | _ -> "This is any other type that wasn't explicitly specified"

Конечно, при сопоставлении с шаблоном F # у вас гораздо больше контроля, чем с простым оператором переключения C #.

0 голосов
/ 01 апреля 2010

Это требует рефакторинга, я бы сказал.

Заменить код типа классом

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...