获得Enum价值的属性

Ale*_*x K 453 c# reflection enums .net-attributes

我想知道是否可以获取枚举值的属性而不是枚举本身的属性?例如,假设我有以下枚举:

using System.ComponentModel; // for DescriptionAttribute

enum FunkyAttributesEnum
{
    [Description("Name With Spaces1")]
    NameWithoutSpaces1,    
    [Description("Name With Spaces2")]
    NameWithoutSpaces2
}
Run Code Online (Sandbox Code Playgroud)

我想要的是枚举类型,产生2元组的枚举字符串值及其描述.

价值很容易:

Array values = System.Enum.GetValues(typeof(FunkyAttributesEnum));
foreach (int value in values)
    Tuple.Value = Enum.GetName(typeof(FunkyAttributesEnum), value);
Run Code Online (Sandbox Code Playgroud)

但是如何获取描述属性的值,以填充Tuple.Desc?如果属性属于枚举本身,我可以想到如何做到这一点,但我不知道如何从枚举的值中获取它.

Bry*_*owe 463

这应该做你需要的.

var enumType = typeof(FunkyAttributesEnum);
var memberInfos = enumType.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString());
var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == enumType);
var valueAttributes = 
      enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
var description = ((DescriptionAttribute)valueAttributes[0]).Description;
Run Code Online (Sandbox Code Playgroud)

  • (可选)使用type.GetFields(BindingFlags.Public | BindingFlags.Static)一次获取所有memInfos. (6认同)
  • 我不得不去打字(FunkyAttributesEnum),但除此之外它运作良好.谢谢. (4认同)
  • @Don,这是OP问题中的枚举成员名称. (2认同)

Ada*_*ord 262

这段代码应该为你提供一个很好的小扩展方法,可以让你检索一个通用属性.我相信它与上面的lambda函数不同,因为它使用起来比较简单 - 你只需要传入泛型类型.

public static class EnumHelper
{
    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="enumVal">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    /// <example>string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description;</example>
    public static T GetAttributeOfType<T>(this Enum enumVal) where T:System.Attribute
    {
        var type = enumVal.GetType();
        var memInfo = type.GetMember(enumVal.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
        return (attributes.Length > 0) ? (T)attributes[0] : null;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 用法为:string desc = myEnumVariable.GetAttributeOfType <DescriptionAttribute>().Description; (18认同)
  • 更好地使用type.GetMember(Enum.GetName(type,enumVal))作为enumVal.ToString()的memInfo对于不同的语言环境可能不可靠. (6认同)
  • 如果没有属性,这不会抛出`IndexOutOfRangeException`吗? (3认同)
  • @tigrou 这个扩展是最近添加到 .NET 框架中的;解决方案(来自 2009 年)可能需要更新。 (3认同)
  • 我比斯科特更喜欢这个,因为这里的用法比较干净(少打字),所以+1 :) (2认同)
  • 调用GetCustomAttributes()然后获取第一个元素而不是调用GetCustomAttribute()有什么意义? (2认同)

小智 80

这是一个使用lambda进行选择的通用实现

public static Expected GetAttributeValue<T, Expected>(this Enum enumeration, Func<T, Expected> expression)
    where T : Attribute
{
    T attribute =
      enumeration
        .GetType()
        .GetMember(enumeration.ToString())
        .Where(member => member.MemberType == MemberTypes.Field)
        .FirstOrDefault()
        .GetCustomAttributes(typeof(T), false)
        .Cast<T>()
        .SingleOrDefault();

    if (attribute == null)
        return default(Expected);

    return expression(attribute);
}
Run Code Online (Sandbox Code Playgroud)

像这样称呼它:

string description = targetLevel.GetAttributeValue<DescriptionAttribute, string>(x => x.Description);
Run Code Online (Sandbox Code Playgroud)

  • 这很棒.如果给定的枚举值是一个组合(由FlagsAttribute`允许),我们必须要小心.在这种情况下,`enumeration.GetType().GetMember(enumeration.ToString())[0]`将失败. (4认同)
  • 我还添加了公共静态字符串GetDescription(此枚举枚举){return enumeration.GetAttributeValue <DescriptionAttribute,String>(x => x.Description); 那样就是它的targetLevel.GetDescription(); (2认同)

Tro*_*ord 62

我在这里合并了几个答案,以创建一个更具可扩展性的解决方案.我提供它是为了防止它对将来的其他人有帮助.原帖在这里.

using System;
using System.ComponentModel;

public static class EnumExtensions {

    // This extension method is broken out so you can use a similar pattern with 
    // other MetaData elements in the future. This is your base method for each.
    public static T GetAttribute<T>(this Enum value) where T : Attribute {
        var type = value.GetType();
        var memberInfo = type.GetMember(value.ToString());
        var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false);
        return attributes.Length > 0 
          ? (T)attributes[0]
          : null;
    }

    // This method creates a specific call to the above method, requesting the
    // Description MetaData attribute.
    public static string ToName(this Enum value) {
        var attribute = value.GetAttribute<DescriptionAttribute>();
        return attribute == null ? value.ToString() : attribute.Description;
    }

}
Run Code Online (Sandbox Code Playgroud)

此解决方案在Enum上创建一对扩展方法.第一个允许您使用反射来检索与您的值相关联的任何属性.第二个特别调用检索DescriptionAttribute并返回它的Description值.

例如,考虑使用DescriptionAttributefrom属性System.ComponentModel

using System.ComponentModel;

public enum Days {
    [Description("Sunday")]
    Sun,
    [Description("Monday")]
    Mon,
    [Description("Tuesday")]
    Tue,
    [Description("Wednesday")]
    Wed,
    [Description("Thursday")]
    Thu,
    [Description("Friday")]
    Fri,
    [Description("Saturday")]
    Sat
}
Run Code Online (Sandbox Code Playgroud)

要使用上述扩展方法,您现在只需调用以下内容:

Console.WriteLine(Days.Mon.ToName());
Run Code Online (Sandbox Code Playgroud)

要么

var day = Days.Mon;
Console.WriteLine(day.ToName());
Run Code Online (Sandbox Code Playgroud)

  • 最好和最简单的答案。 (3认同)
  • 我喜欢这个解决方案,但是其中有一个错误。GetAttribute方法假定枚举值具有Description属性,因此当属性长度为0时引发异常。替换为“ return(T)attributes [0];”。与“返回(attributes.Length&gt; 0?(T)attributes [0]:null);” (2认同)

Fun*_*ame 38

除了AdamCrawford响应之外,我还进一步创建了一个更专业的扩展方法,通过它来获取描述.

public static string GetAttributeDescription(this Enum enumValue)
{
    var attribute = enumValue.GetAttributeOfType<DescriptionAttribute>();
    return attribute == null ? String.Empty : attribute.Description;
} 
Run Code Online (Sandbox Code Playgroud)

因此,要获得描述,您可以使用原始扩展方法作为

string desc = myEnumVariable.GetAttributeOfType<DescriptionAttribute>().Description
Run Code Online (Sandbox Code Playgroud)

或者你可以简单地在这里调用扩展方法:

string desc = myEnumVariable.GetAttributeDescription();
Run Code Online (Sandbox Code Playgroud)

哪个应该有希望使您的代码更具可读性.


Ayd*_*din 14

流利的一个班轮......

这里我使用的DisplayAttribute包含NameDescription属性.

public static DisplayAttribute GetDisplayAttributesFrom(this Enum enumValue, Type enumType)
{
    return enumType.GetMember(enumValue.ToString())
                   .First()
                   .GetCustomAttribute<DisplayAttribute>();
}
Run Code Online (Sandbox Code Playgroud)

public enum ModesOfTransport
{
    [Display(Name = "Driving",    Description = "Driving a car")]        Land,
    [Display(Name = "Flying",     Description = "Flying on a plane")]    Air,
    [Display(Name = "Sea cruise", Description = "Cruising on a dinghy")] Sea
}

void Main()
{
    ModesOfTransport TransportMode = ModesOfTransport.Sea;
    DisplayAttribute metadata = TransportMode.GetDisplayAttributesFrom(typeof(ModesOfTransport));
    Console.WriteLine("Name: {0} \nDescription: {1}", metadata.Name, metadata.Description);
}
Run Code Online (Sandbox Code Playgroud)

产量

Name: Sea cruise 
Description: Cruising on a dinghy
Run Code Online (Sandbox Code Playgroud)

  • 我也用这个,它是所有答案中最干净的!+1 (3认同)

Col*_*lin 7

以下是从Display属性获取信息的代码.它使用通用方法来检索属性.如果未找到该属性,则将enum值转换为将pascal/camel case转换为title case的字符串(此处获取的代码)

public static class EnumHelper
{
    // Get the Name value of the Display attribute if the   
    // enum has one, otherwise use the value converted to title case.  
    public static string GetDisplayName<TEnum>(this TEnum value)
        where TEnum : struct, IConvertible
    {
        var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
        return attr == null ? value.ToString().ToSpacedTitleCase() : attr.Name;
    }

    // Get the ShortName value of the Display attribute if the   
    // enum has one, otherwise use the value converted to title case.  
    public static string GetDisplayShortName<TEnum>(this TEnum value)
        where TEnum : struct, IConvertible
    {
        var attr = value.GetAttributeOfType<TEnum, DisplayAttribute>();
        return attr == null ? value.ToString().ToSpacedTitleCase() : attr.ShortName;
    }

    /// <summary>
    /// Gets an attribute on an enum field value
    /// </summary>
    /// <typeparam name="TEnum">The enum type</typeparam>
    /// <typeparam name="T">The type of the attribute you want to retrieve</typeparam>
    /// <param name="value">The enum value</param>
    /// <returns>The attribute of type T that exists on the enum value</returns>
    private static T GetAttributeOfType<TEnum, T>(this TEnum value)
        where TEnum : struct, IConvertible
        where T : Attribute
    {

        return value.GetType()
                    .GetMember(value.ToString())
                    .First()
                    .GetCustomAttributes(false)
                    .OfType<T>()
                    .LastOrDefault();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是转换为标题案例的字符串的扩展方法:

    /// <summary>
    /// Converts camel case or pascal case to separate words with title case
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static string ToSpacedTitleCase(this string s)
    {
        //https://stackoverflow.com/a/155486/150342
        CultureInfo cultureInfo = Thread.CurrentThread.CurrentCulture;
        TextInfo textInfo = cultureInfo.TextInfo;
        return textInfo
           .ToTitleCase(Regex.Replace(s, 
                        "([a-z](?=[A-Z0-9])|[A-Z](?=[A-Z][a-z]))", "$1 "));
    }
Run Code Online (Sandbox Code Playgroud)


Pri*_*wen 5

如果您enum包含这样的值,Equals那么您可能会在此处的许多答案中使用某些扩展来遇到一些错误。这是因为通常假设typeof(YourEnum).GetMember(YourEnum.Value)只会返回一个值,即MemberInfo您的enum. 这是亚当·克劳福德(Adam Crawford)的答案的一个稍微安全的版本。

public static class AttributeExtensions
{
    #region Methods

    public static T GetAttribute<T>(this Enum enumValue) where T : Attribute
    {
        var type = enumValue.GetType();
        var memberInfo = type.GetMember(enumValue.ToString());
        var member = memberInfo.FirstOrDefault(m => m.DeclaringType == type);
        var attribute = Attribute.GetCustomAttribute(member, typeof(T), false);
        return attribute is T ? (T)attribute : null;
    }

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

编辑(2023 年 5 月 3 日)

GetField在这种情况下效果很好。typeof(YourEnum).GetField(YourEnum.Value)应该产生期望的结果。

public static T GetAttribute<T>(this Enum value) where T : Attribute
{
    Type type = value.GetType();
    FieldInfo field = type.GetField(value.ToString());

    Attribute attr = Attribute.GetCustomAttribute(field, typeof(T), false);
    return (T)attr;
}
Run Code Online (Sandbox Code Playgroud)

感谢mjwills指出这一点。


Jin*_*nov 5

对于一些程序员的幽默来说,有一句笑话:

public static string GetDescription(this Enum value) => value.GetType().GetMember(value.ToString()).First().GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute ? attribute.Description : string.Empty;
Run Code Online (Sandbox Code Playgroud)

以更易读的形式:

using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

public static class EnumExtensions
{
    // get description from enum:

    public static string GetDescription(this Enum value)
    {
        return value.GetType().
            GetMember(value.ToString()).
            First().
            GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute
            ? attribute.Description
            : throw new Exception($"Enum member '{value.GetType()}.{value}' doesn't have a [DescriptionAttribute]!");
    }

    // get enum from description:

    public static T GetEnum<T>(this string description) where T : Enum
    {
        foreach (FieldInfo fieldInfo in typeof(T).GetFields())
        {
            if (fieldInfo.GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute && attribute.Description == description)
                return (T)fieldInfo.GetRawConstantValue();
        }

        throw new Exception($"Enum '{typeof(T)}' doesn't have a member with a [DescriptionAttribute('{description}')]!");
    }
}
Run Code Online (Sandbox Code Playgroud)