字符串到枚举说明

时间:2010-11-22 19:56:07

标签: c# enums

我目前正在基于this suggestion实现字符串和枚举的关联。就是这样,我有一个Description属性与每个枚举元素相关联。在该页面上还有一个函数,它根据给定的枚举返回描述的字符串。我现在要实现的是反向函数,也就是说,给定一个输入字符串查找带有相应描述的枚举(如果存在),否则返回null。

我尝试了(T) Enum.Parse(typeof(T), "teststring"),但它会抛出异常。

5 个答案:

答案 0 :(得分:14)

你必须编写自己的反向方法。库存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");
}

但是,如果找不到枚举值,你会想要找到一个更好的事情而不是抛出异常。 :)

答案 1 :(得分:2)

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

答案 2 :(得分:1)

我会赞成安娜的回答,但我没有这样做的声誉。部分基于她的答案,这是我提出的双向解决方案。向ParseEnum方法提供defaultValue可以涵盖相同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;            
    }

答案 3 :(得分:1)

您也可以使用Humanizer。要获得您所写的描述:

EAssemblyUnit.eUCAL1.Humanize();

并从描述中获取枚举,这是你想要的,你可以写:

"UCAL1".DehumanizeTo<EAssemblyUnit>();

免责声明:我是Humanizer的创作者。

答案 4 :(得分:0)

This answer相关问题显示了如何检索给定类型的属性。您可以使用类似的方法将给定字符串与Enum的描述属性进行比较。