Строка для перечисления с описанием - PullRequest
7 голосов
/ 22 ноября 2010

В настоящее время я реализую ассоциацию строк и перечислений на основе этого предложения . Таким образом, у меня есть атрибут Description, связанный с каждым элементом enum. На этой странице также есть функция, которая возвращает строку описания на основе заданного перечисления. Теперь я хотел бы реализовать обратную функцию, то есть, если во входной строке выполнить поиск по перечислению с соответствующим описанием, если оно существует, в противном случае вернуть ноль.

Я пытался (T) Enum.Parse(typeof(T), "teststring"), но выдает исключение.

Ответы [ 5 ]

15 голосов
/ 22 ноября 2010

Вы должны написать свой собственный обратный метод. Стандартный метод Parse () явно не знает о ваших атрибутах описания.

Примерно так должно работать:

public static T GetEnumValueFromDescription<T>(string description)
{
    MemberInfo[] fis = typeof(T).GetFields();

    foreach (var fi in fis)
    {
        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

        if (attributes != null && attributes.Length > 0 && attributes[0].Description == description)
            return (T)Enum.Parse(typeof(T), fi.Name);
    }

    throw new Exception("Not found");
}

Возможно, вы захотите найти лучшую вещь, чем генерировать исключение, если значение enum не найдено :)

2 голосов
/ 22 ноября 2010
static string GetEnumDescription<T>(T value) {
    FieldInfo fi = value.GetType().GetField(value.ToString());

    DescriptionAttribute[] attributes =
        (DescriptionAttribute[])fi.GetCustomAttributes(
            typeof(DescriptionAttribute),
            false
    );

    if (attributes != null &&
        attributes.Length > 0) {
        return attributes[0].Description;
    }
    else {
        return value.ToString();
    }
}

static T ParseDescriptionToEnum<T>(string description) {
    Array array = Enum.GetValues(typeof(T));
    var list = new List<T>(array.Length);
    for(int i = 0; i < array.Length; i++) {
        list.Add((T)array.GetValue(i));
    }

    var dict = list.Select(v => new { 
                   Value = v,
                   Description = GetEnumDescription(v) }
               )
                   .ToDictionary(x => x.Description, x => x.Value);
    return dict[description];
}

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

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

enum SomeEnum {
    [Description("First Value")]
    FirstValue,
    SecondValue
}

SomeEnum value = ParseDescriptionToEnum<SomeEnum>("First Value");

Тест, который проходит:

[Fact]
public void Can_parse_a_value_with_a_description_to_an_enum() {
    string description = "First Value";
    SomeEnum value = ParseDescriptionToEnum<SomeEnum>(description);
    Assert.Equal(SomeEnum.FirstValue, value);
}

[Fact]
public void Can_parse_a_value_without_a_description_to_an_enum() {
    string description = "SecondValue";
    SomeEnum value = ParseDescriptionToEnum<SomeEnum>(description);
    Assert.Equal(SomeEnum.SecondValue, value);
}
1 голос
/ 06 сентября 2013

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

EAssemblyUnit.eUCAL1.Humanize();

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

"UCAL1".DehumanizeTo<EAssemblyUnit>();

Отказ от ответственности: Я являюсьСоздатель Humanizer.

1 голос
/ 09 июля 2013

Я бы проголосовал за ответ Анны, но у меня нет такой репутации. Часть этого, основанная на ее ответе, дает мне двухстороннее решение. Предоставление метода defaultValue для ParseEnum охватывает случаи, когда один и тот же Enum может иметь другое значение по умолчанию в зависимости от его использования.

    public static string GetDescription<T>(this object enumerationValue) where T : struct
    {
        // throw an exception if enumerationValue is not an Enum
        Type type = enumerationValue.GetType();
        if (!type.IsEnum)
        {
            throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
        }

        //Tries to find a DescriptionAttribute for a potential friendly name for the enum
        MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
        if (memberInfo != null && memberInfo.Length > 0)
        {
            DescriptionAttribute[] attributes = (DescriptionAttribute[])memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attributes != null && attributes.Length > 0)
            {
                //Pull out the description value
                return attributes[0].Description;
            }
        }

        //In case we have no description attribute, we'll just return the ToString of the enum
        return enumerationValue.ToString();
    }

    public static T ParseEnum<T>(this string stringValue, T defaultValue)
    {
        // throw an exception if T is not an Enum
        Type type = typeof(T);
        if (!type.IsEnum)
        {
            throw new ArgumentException("T must be of Enum type", "T");
        }

        //Tries to find a DescriptionAttribute for a potential friendly name for the enum
        MemberInfo[] fields = type.GetFields();

        foreach (var field in fields)
        {
            DescriptionAttribute[] attributes = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), false);

            if (attributes != null && attributes.Length > 0 && attributes[0].Description == stringValue)
            {
                return (T)Enum.Parse(typeof(T), field.Name);
            }
        }

        //In case we couldn't find a matching description attribute, we'll just return the defaultValue that we provided
        return defaultValue;            
    }
0 голосов
/ 22 ноября 2010

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

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