Связывание перечислений со строками в C # - PullRequest
264 голосов
/ 10 марта 2009

Я знаю, что следующее невозможно, потому что оно должно быть int

enum GroupTypes
{
    TheGroup = "OEM",
    TheOtherGroup = "CMB"
}

Из моей базы данных я получаю поле с непонятными кодами (OEM и CMB). Я хотел бы превратить это поле в перечисление или что-то еще понятное. Поскольку целью является удобочитаемость, решение должно быть кратким.
Какие еще варианты у меня есть?

Ответы [ 28 ]

290 голосов
/ 28 августа 2009

Мне нравится использовать свойства в классе вместо методов, так как они выглядят более перечислимыми.

Вот пример для Logger:

public class LogCategory
{
 private LogCategory(string value) { Value = value; }

 public string Value { get; set; }

 public static LogCategory Trace { get { return new LogCategory("Trace"); } }
 public static LogCategory Debug { get { return new LogCategory("Debug"); } }
 public static LogCategory Info { get { return new LogCategory("Info"); } }
 public static LogCategory Warning { get { return new LogCategory("Warning"); } }
 public static LogCategory Error { get { return new LogCategory("Error"); } }
}

Передать типобезопасные строковые значения в качестве параметра:

public static void Write(string message, LogCategory logCategory)
{
   var log = new LogEntry { Message = message };
   Logger.Write(log, logCategory.Value);
}

Использование:

Logger.Write("This is almost like an enum.", LogCategory.Info);
133 голосов
/ 10 марта 2009

Вы также можете использовать модель расширения:

public enum MyEnum
{
    [Description("String 1")]
    V1= 1,
    [Description("String 2")]
    V2= 2
} 

Ваш добавочный класс

public static class MyEnumExtensions
{
    public static string ToDescriptionString(this MyEnum val)
    {
        DescriptionAttribute[] attributes = (DescriptionAttribute[])val
           .GetType()
           .GetField(val.ToString())
           .GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : string.Empty;
    }
} 

использование:

MyEnum myLocal = MyEnum.V1;
print(myLocal.ToDescriptionString());
76 голосов
/ 15 апреля 2011

Как насчет использования статического класса с константами? Код клиента не будет отличаться от перечислений.

static class GroupTypes
{
  public const string TheGroup = "OEM";
  public const string TheOtherGroup = "CMB";
}

void DoSomething(GroupTypes groupType)
{
  if(groupType == GroupTypes.TheOtherGroup)
  {
    //Launch nuclear bomb 
  }  
}
28 голосов
/ 10 марта 2009

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

Вы должны использовать спецификатор "field" для применения атрибутов, например так:

enum GroupTypes
{
    [field:Description("OEM")]
    TheGroup,

    [field:Description("CMB")]
    TheOtherGroup
}

Затем вы бы отразили статические поля типа перечисления (в данном случае GroupTypes) и получили бы DescriptionAttribute для значения, которое вы искали, используя отражение:

public static DescriptionAttribute GetEnumDescriptionAttribute<T>(
    this T value) where T : struct
{
    // The type of the enum, it will be reused.
    Type type = typeof(T);

    // If T is not an enum, get out.
    if (!type.IsEnum) 
        throw new InvalidOperationException(
            "The type parameter T must be an enum type.");

    // If the value isn't defined throw an exception.
    if (!Enum.IsDefined(type, value))
        throw new InvalidEnumArgumentException(
            "value", Convert.ToInt32(value), type);

    // Get the static field for the value.
    FieldInfo fi = type.GetField(value.ToString(), 
        BindingFlags.Static | BindingFlags.Public);

    // Get the description attribute, if there is one.
    return fi.GetCustomAttributes(typeof(DescriptionAttribute), true).
        Cast<DescriptionAttribute>().SingleOrDefault();
}

Я решил вернуть сам DescriptionAttribute выше, в случае, если вы хотите определить, применяется ли атрибут или нет.

19 голосов
/ 05 декабря 2009

Вы можете сделать это очень легко на самом деле. Используйте следующий код.

enum GroupTypes
{
   OEM,
   CMB
};

Затем, когда вы хотите получить строковое значение каждого элемента перечисления, просто используйте следующую строку кода.

String oemString = Enum.GetName(typeof(GroupTypes), GroupTypes.OEM);

В прошлом я успешно использовал этот метод, а также использовал класс констант для хранения строковых констант, оба работают довольно хорошо, но я склоняюсь к этому.

13 голосов
/ 10 марта 2009

Создайте второе перечисление для вашей БД, содержащее следующее:

enum DBGroupTypes
{
    OEM = 0,
    CMB = 1
}

Теперь вы можете использовать Enum.Parse для получения правильного значения DBGroupTypes из строк «OEM» и «CMB». Затем вы можете преобразовать их в int и извлечь правильные значения из правильного перечисления, которое вы хотите использовать в своей модели.

10 голосов
/ 10 марта 2009

Используйте класс.

Редактировать: лучший пример

class StarshipType
{
    private string _Name;
    private static List<StarshipType> _StarshipTypes = new List<StarshipType>();

    public static readonly StarshipType Ultralight = new StarshipType("Ultralight");
    public static readonly StarshipType Light = new StarshipType("Light");
    public static readonly StarshipType Mediumweight = new StarshipType("Mediumweight");
    public static readonly StarshipType Heavy = new StarshipType("Heavy");
    public static readonly StarshipType Superheavy = new StarshipType("Superheavy");

    public string Name
    {
        get { return _Name; }
        private set { _Name = value; }
    }

    public static IList<StarshipType> StarshipTypes
    {
        get { return _StarshipTypes; }
    }

    private StarshipType(string name, int systemRatio)
    {
        Name = name;
        _StarshipTypes.Add(this);
    }

    public static StarshipType Parse(string toParse)
    {
        foreach (StarshipType s in StarshipTypes)
        {
            if (toParse == s.Name)
                return s;
        }
        throw new FormatException("Could not parse string.");
    }
}
8 голосов
/ 10 марта 2009

Попробуйте добавить константы в статический класс. Вы не получите Type, но у вас есть читаемые организованные константы:

public static class GroupTypes
{
    public const string TheGroup = "OEM";
    public const string TheOtherGroup = "CMB"
}
6 голосов
/ 16 марта 2010

Вот метод расширения, который я использовал для получения значения enum в виде строки. Сначала вот перечисление.

public enum DatabaseEnvironment
{
    [Description("AzamSharpBlogDevDatabase")]
    Development = 1, 
    [Description("AzamSharpBlogQADatabase")]
    QualityAssurance = 2, 
    [Description("AzamSharpBlogTestDatabase")] 
    Test = 3
}

Атрибут Description получен из System.ComponentModel.

А вот мой метод расширения:

public static string GetValueAsString(this DatabaseEnvironment environment) 
{
    // get the field 
    var field = environment.GetType().GetField(environment.ToString());
    var customAttributes = field.GetCustomAttributes(typeof (DescriptionAttribute), false);

    if(customAttributes.Length > 0)
    {
        return (customAttributes[0] as DescriptionAttribute).Description;  
    }
    else
    {
        return environment.ToString(); 
    }
}

Теперь вы можете получить доступ к перечислению как строковому значению, используя следующий код:

[TestFixture]
public class when_getting_value_of_enum
{
    [Test]
    public void should_get_the_value_as_string()
    {
        Assert.AreEqual("AzamSharpBlogTestDatabase",DatabaseEnvironment.Test.GetValueAsString());  
    }
}
6 голосов
/ 29 декабря 2017

Другой способ справиться с проблемой - это иметь перечисление и массив строк, которые будут отображать значения перечисления в список строк:

public enum GroupTypes
{
    TheGroup  = 0,
    TheOtherGroup 
}

string[] GroupTypesStr = {
    "OEM",
    "CMB"
};

Вы можете использовать что-то вроде этого:

Log.Write(GroupTypesStr[(int)GroupTypes.TheOtherGroup]);

Это подскажет CMB

ПЛЮСЫ:

  1. Простой и понятный код.
  2. Высокая производительность (особенно по сравнению с теми подходами, которые использует классы)

МИНУСЫ:

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