Getting attributes of Enum's value

后端 未结 25 2578
慢半拍i
慢半拍i 2020-11-22 00:35

I would like to know if it is possible to get attributes of the enum values and not of the enum itself? For example, suppose I have the following <

相关标签:
25条回答
  • 2020-11-22 01:11

    Alternatively, you could do the following:

    List<SelectListItem> selectListItems = new List<SelectListItem>();
    
        foreach (var item in typeof(PaymentTerm).GetEnumValues())
        {
            var type = item.GetType();
            var name = type.GetField(item.ToString()).GetCustomAttributesData().FirstOrDefault()?.NamedArguments.FirstOrDefault().TypedValue.Value.ToString();
            selectListItems.Add(new SelectListItem(name, type.Name));
    
        }
    
    0 讨论(0)
  • 2020-11-22 01:12

    Here is code to get information from a Display attribute. It uses a generic method to retrieve the attribute. If the attribute is not found it converts the enum value to a string with pascal/camel case converted to title case (code obtained here)

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

    And this is the extension method for strings for converting to title case:

        /// <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 "));
        }
    
    0 讨论(0)
  • 2020-11-22 01:12

    Here's the .NET Core version of AdamCrawford's answer, using System.Reflection.TypeExtensions;

    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());
            IEnumerable<Attribute> attributes = memInfo[0].GetCustomAttributes(typeof(T), false);
            return (T)attributes?.ToArray()[0];
        }
    }
    
    0 讨论(0)
  • 2020-11-22 01:12

    Alternatively, you could do the following:

    Dictionary<FunkyAttributesEnum, string> description = new Dictionary<FunkyAttributesEnum, string>()
        {
          { FunkyAttributesEnum.NameWithoutSpaces1, "Name With Spaces1" },
          { FunkyAttributesEnum.NameWithoutSpaces2, "Name With Spaces2" },
        };
    

    And get the description with the following:

    string s = description[FunkyAttributesEnum.NameWithoutSpaces1];
    

    In my opinion this is a more efficient way of doing what you want to accomplish, as no reflection is needed..

    0 讨论(0)
  • 2020-11-22 01:13

    Fluent one liner...

    Here I'm using the DisplayAttribute which contains both the Name and Description properties.

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

    Example

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

    Output

    Name: Sea cruise 
    Description: Cruising on a dinghy
    
    0 讨论(0)
  • 2020-11-22 01:15

    Guys if it helps I will share with you my solution: Definition of Custom attribute:

        [AttributeUsage(AttributeTargets.Field,AllowMultiple = false)]
    public class EnumDisplayName : Attribute
    {
        public string Name { get; private set; }
        public EnumDisplayName(string name)
        {
            Name = name;
        }
    }
    

    Now because I needed it inside of HtmlHelper definition of HtmlHelper Extension:

    public static class EnumHelper
    {
        public static string EnumDisplayName(this HtmlHelper helper,EPriceType priceType)
        {
            //Get every fields from enum
            var fields = priceType.GetType().GetFields();
            //Foreach field skipping 1`st fieldw which keeps currently sellected value
            for (int i = 0; i < fields.Length;i++ )
            {
                //find field with same int value
                if ((int)fields[i].GetValue(priceType) == (int)priceType)
                {
                    //get attributes of found field
                    var attributes = fields[i].GetCustomAttributes(false);
                    if (attributes.Length > 0)
                    {
                        //return name of found attribute
                        var retAttr = (EnumDisplayName)attributes[0];
                        return retAttr.Name;
                    }
                }
            }
            //throw Error if not found
            throw new Exception("Błąd podczas ustalania atrybutów dla typu ceny allegro");
        }
    }
    

    Hope it helps

    0 讨论(0)
提交回复
热议问题