关于c#:从枚举属性中获取枚举

Get enum from enum attribute

我已经得到

1
2
3
4
5
6
7
public enum Als
{
    [StringValue("Beantwoord")] Beantwoord = 0,
    [StringValue("Niet beantwoord")] NietBeantwoord = 1,
    [StringValue("Geselecteerd")] Geselecteerd = 2,
    [StringValue("Niet geselecteerd")] NietGeselecteerd = 3,
}

具有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StringValueAttribute : Attribute
{
    private string _value;

    public StringValueAttribute(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }
}

我想把我从一个组合框中选择的项的值放入一个int中:

1
int i = (int)(Als)Enum.Parse(typeof(Als), (string)cboAls.SelectedValue); //<- WRONG

这可能吗?如果可能,怎么可能?(StringValue与从组合框中选择的值匹配)。


下面是一个帮助器方法,它应该为您指明正确的方向。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected Als GetEnumByStringValueAttribute(string value)
{
    Type enumType = typeof(Als);
    foreach (Enum val in Enum.GetValues(enumType))
    {
        FieldInfo fi = enumType.GetField(val.ToString());
        StringValueAttribute[] attributes = (StringValueAttribute[])fi.GetCustomAttributes(
            typeof(StringValueAttribute), false);
        StringValueAttribute attr = attributes[0];
        if (attr.Value == value)
        {
            return (Als)val;
        }
    }
    throw new ArgumentException("The value '" + value +"' is not supported.");
}

要调用它,只需执行以下操作:

1
Als result = this.GetEnumByStringValueAttribute<Als>(ComboBox.SelectedValue);

虽然这可能不是最好的解决方案,因为它与Als绑定在一起,您可能希望使此代码可重用。您可能希望从我的解决方案中去掉代码以返回属性值,然后像处理问题一样使用Enum.Parse


我正在使用Microsoft的DescriptionAttribute和以下扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static string GetDescription(this Enum value)
{
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }

    string description = value.ToString();
    FieldInfo fieldInfo = value.GetType().GetField(description);
    DescriptionAttribute[] attributes =
       (DescriptionAttribute[])
     fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);

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


这里有几个扩展方法,我正是为了这个目的而使用的,我已经重写了这些方法来使用您的StringValueAttribute,但是像奥利弗一样,我在代码中使用了descriptionattribute。

1
2
3
4
5
6
7
8
9
10
11
    public static T FromEnumStringValue<T>(this string description) where T : struct {
        Debug.Assert(typeof(T).IsEnum);

        return (T)typeof(T)
            .GetFields()
            .First(f => f.GetCustomAttributes(typeof(StringValueAttribute), false)
                         .Cast<StringValueAttribute>()
                         .Any(a => a.Value.Equals(description, StringComparison.OrdinalIgnoreCase))
            )
            .GetValue(null);
    }

这可以在.NET 4.5中稍微简单一点:

1
2
3
4
5
6
7
8
9
10
    public static T FromEnumStringValue<T>(this string description) where T : struct {
        Debug.Assert(typeof(T).IsEnum);

        return (T)typeof(T)
            .GetFields()
            .First(f => f.GetCustomAttributes<StringValueAttribute>()
                         .Any(a => a.Value.Equals(description, StringComparison.OrdinalIgnoreCase))
            )
            .GetValue(null);
    }

要调用它,只需执行以下操作:

1
Als result = ComboBox.SelectedValue.FromEnumStringValue<Als>();

相反,这里有一个从枚举值中获取字符串的函数:

1
2
3
4
5
6
7
8
    public static string StringValue(this Enum enumItem) {
        return enumItem
            .GetType()
            .GetField(enumItem.ToString())
            .GetCustomAttributes<StringValueAttribute>()
            .Select(a => a.Value)
            .FirstOrDefault() ?? enumItem.ToString();
    }

并称之为:

1
string description = Als.NietBeantwoord.StringValue()

从这个高度乐观的问题和答案的重复链接来看,这里有一个方法可以与C 7.3的新Enum类型约束一起工作。请注意,您还需要指定它也是一个struct,这样您就可以将其设置为可以为空的TEnum?,否则您将得到一个错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static TEnum? GetEnumFromDescription<TEnum>(string description)
    where TEnum : struct, Enum
{
    var comparison = StringComparison.OrdinalIgnoreCase;
    foreach (var field in typeof(TEnum).GetFields())
    {
        var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
        if (attribute != null)
        {
            if (string.Compare(attribute.Description, description, comparison) == 0)
                return (TEnum)field.GetValue(null);
        }
        if (string.Compare(field.Name, description, comparison) == 0)
            return (TEnum)field.GetValue(null);
    }
    return null;
}

不知道我是否在这里遗漏了什么,你能不能不这样做?

1
2
Als temp = (Als)combo1.SelectedItem;
int t = (int)temp;

要基于应用于枚举成员的属性值分析字符串值,我建议您使用我的enums.net开放源代码库。

对于像StringValueAttribute这样的自定义属性,您可以这样做。

注册并存储用于StringValueAttribute.Value的自定义EnumFormat

1
Format = Enums.RegisterCustomEnumFormat(m => m.Attributes.Get<StringValueAttribute>()?.Value);

然后使用自定义EnumFormat

1
Als result = Enums.Parse<Als>("Niet beantwoord", Format); // result == Als.NietBeantwoord

如果您使用的是诸如DescriptionAttribute这样的内置属性,则可以这样做。

1
Als result = Enums.Parse<Als>("Niet beantwoord", EnumFormat.Description);

如果您感兴趣,这是获取与枚举值关联的字符串值的方法。

1
string value = Als.NietBeantwoord.AsString(Format); // value =="Niet beantwoord"