Получение атрибутов значения Enum

Я хотел бы знать, можно ли получить атрибуты значений enums, а не самого enums? Например, предположим, что у меня есть следующее перечисление:

using System.ComponentModel; // for DescriptionAttribute enum FunkyAttributesEnum { [Description("Name With Spaces1")] NameWithoutSpaces1, [Description("Name With Spaces2")] NameWithoutSpaces2 } 

То, что я хочу, задается типом enums, выдает 2-строчные значения строки enums и ее описание.

Ценность была легко:

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

Но как мне получить значение атрибута описания, чтобы заполнить Tuple.Desc? Я могу подумать, как это сделать, если атрибут принадлежит самому перечислению, но я не понимаю, как получить его из значения enums.

Это должно делать то, что вам нужно.

 var type = typeof(FunkyAttributesEnum); var memInfo = type.GetMember(FunkyAttributesEnum.NameWithoutSpaces1.ToString()); var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); var description = ((DescriptionAttribute)attributes[0]).Description; 

Этот fragment кода должен дать вам небольшой метод расширения для любого enums, который позволит вам получить общий атрибут. Я считаю, что это отличается от функции lambda выше, потому что ее проще использовать и немного – вам нужно только передать общий тип.

 public static class EnumHelper { ///  /// Gets an attribute on an enum field value ///  /// The type of the attribute you want to retrieve /// The enum value /// The attribute of type T that exists on the enum value /// string desc = myEnumVariable.GetAttributeOfType().Description; public static T GetAttributeOfType(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; } } 

Это общая реализация с использованием lambda для выбора

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

Назовите это так:

 string description = targetLevel.GetAttributeValue(x => x.Description); 

Я объединил пару ответов здесь, чтобы создать немного более расширяемое решение. Я предоставляю его на всякий случай, если он будет полезен кому-либо еще в будущем. Оригинальная публикация здесь .

 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(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 (T)attributes[0]; } // 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(); return attribute == null ? value.ToString() : attribute.Description; } } 

Это решение создает пару методов расширения для Enum. Первый позволяет использовать reflection для извлечения любого атрибута, связанного с вашим значением. Второй особый вызов возвращает атрибут DescriptionAttribute и возвращает его значение Description .

В качестве примера рассмотрим использование атрибута DescriptionAttribute из 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 } 

Чтобы использовать вышеупомянутый метод расширения, вы теперь просто вызываете следующее:

 Console.WriteLine(Days.Mon.ToName()); 

или

 var day = Days.Mon; Console.WriteLine(day.ToName()); 

В дополнение к ответу AdamCrawford , я также создал более специализированные методы расширения, которые поддерживают его, чтобы получить описание.

 public static string GetAttributeDescription(this Enum enumValue) { var attribute = enumValue.GetAttributeOfType(); return attribute == null ? String.Empty : attribute.Description; } 

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

 string desc = myEnumVariable.GetAttributeOfType().Description 

или вы можете просто вызвать метод расширения здесь как:

 string desc = myEnumVariable.GetAttributeDescription(); 

Который должен надеяться сделать ваш код немного более удобочитаемым.

Свободный один вкладыш …

Здесь я использую DisplayAttribute который содержит свойства Name и Description .

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

пример

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

Вывод

 Name: Sea cruise Description: Cruising on a dinghy 

Вот код для получения информации из атрибута Display. Он использует общий метод для извлечения атрибута. Если атрибут не найден, он преобразует значение enums в строку с флагом pascal / camel, преобразованным в регистр заголовка (код, полученный здесь )

 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(this TEnum value) where TEnum : struct, IConvertible { var attr = value.GetAttributeOfType(); 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(this TEnum value) where TEnum : struct, IConvertible { var attr = value.GetAttributeOfType(); return attr == null ? value.ToString().ToSpacedTitleCase() : attr.ShortName; } ///  /// Gets an attribute on an enum field value ///  /// The enum type /// The type of the attribute you want to retrieve /// The enum value /// The attribute of type T that exists on the enum value private static T GetAttributeOfType(this TEnum value) where TEnum : struct, IConvertible where T : Attribute { return value.GetType() .GetMember(value.ToString()) .First() .GetCustomAttributes(false) .OfType() .LastOrDefault(); } } 

И это метод расширения для строк для преобразования в заголовок:

  ///  /// Converts camel case or pascal case to separate words with title case ///  ///  ///  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, "([az](?=[A-Z0-9])|[AZ](?=[AZ][az]))", "$1 ")); } 

Получить словарь из enums.

 public static IDictionary ToDictionary(this Type enumType) { return Enum.GetValues(enumType) .Cast() .ToDictionary(v => ((Enum)v).ToEnumDescription(), k => (int)k); } 

Теперь назовите это как …

 var dic = typeof(ActivityType).ToDictionary(); 

Метод EnumDecription Ext

 public static string ToEnumDescription(this Enum en) //ext method { Type type = en.GetType(); MemberInfo[] memInfo = type.GetMember(en.ToString()); if (memInfo != null && memInfo.Length > 0) { object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); if (attrs != null && attrs.Length > 0) return ((DescriptionAttribute)attrs[0]).Description; } return en.ToString(); } public enum ActivityType { [Description("Drip Plan Email")] DripPlanEmail = 1, [Description("Modification")] Modification = 2, [Description("View")] View = 3, [Description("E-Alert Sent")] EAlertSent = 4, [Description("E-Alert View")] EAlertView = 5 } 

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

 public static class EnumExtension { public static string ToDescription(this System.Enum value) { FieldInfo fi = value.GetType().GetField(value.ToString()); var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); return attributes.Length > 0 ? attributes[0].Description : value.ToString(); } } 

Вот версия .NET Core для ответа AdamCrawford, используя System.Reflection.TypeExtensions ;

 public static class EnumHelper { ///  /// Gets an attribute on an enum field value ///  /// The type of the attribute you want to retrieve /// The enum value /// The attribute of type T that exists on the enum value /// string desc = myEnumVariable.GetAttributeOfType().Description; public static T GetAttributeOfType(this Enum enumVal) where T : System.Attribute { var type = enumVal.GetType(); var memInfo = type.GetMember(enumVal.ToString()); IEnumerable attributes = memInfo[0].GetCustomAttributes(typeof(T), false); return (T)attributes?.ToArray()[0]; } } 

Добавление моего решения для Net Framework и NetCore.

Я использовал это для моей реализации Net Framework:

 public static class EnumerationExtension { public static string Description( this Enum value ) { // get attributes var field = value.GetType().GetField( value.ToString() ); var attributes = field.GetCustomAttributes( typeof( DescriptionAttribute ), false ); // return description return attributes.Any() ? ( (DescriptionAttribute)attributes.ElementAt( 0 ) ).Description : "Description Not Found"; } } 

Это не работает для NetCore, поэтому я изменил его, чтобы сделать это:

 public static class EnumerationExtension { public static string Description( this Enum value ) { // get attributes var field = value.GetType().GetField( value.ToString() ); var attributes = field.GetCustomAttributes( false ); // Description is in a hidden Attribute class called DisplayAttribute // Not to be confused with DisplayNameAttribute dynamic displayAttribute = null; if (attributes.Any()) { displayAttribute = attributes.ElementAt( 0 ); } // return description return displayAttribute?.Description ?? "Description Not Found"; } } 

Пример enums:

 public enum ExportTypes { [Display( Name = "csv", Description = "text/csv" )] CSV = 0 } 

Пример использования для статического добавленного:

 var myDescription = myEnum.Description(); 

Воспользовавшись некоторыми новыми функциями языка C #, вы можете уменьшить количество строк:

 public static TAttribute GetEnumAttribute(this Enum enumVal) where TAttribute : Attribute { var memberInfo = enumVal.GetType().GetMember(enumVal.ToString()); return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false).OfType().FirstOrDefault(); } public static string GetEnumDescription(this Enum enumValue) => enumValue.GetEnumAttribute()?.Description ?? enumValue.ToString(); 

Этот метод расширения получит строковое представление значения enums, используя его XmlEnumAttribute. Если XmlEnumAttribute не присутствует, он возвращается к enum.ToString ().

 public static string ToStringUsingXmlEnumAttribute(this T enumValue) where T: struct, IConvertible { if (!typeof(T).IsEnum) { throw new ArgumentException("T must be an enumerated type"); } string name; var type = typeof(T); var memInfo = type.GetMember(enumValue.ToString()); if (memInfo.Length == 1) { var attributes = memInfo[0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false); if (attributes.Length == 1) { name = ((System.Xml.Serialization.XmlEnumAttribute)attributes[0]).Name; } else { name = enumValue.ToString(); } } else { name = enumValue.ToString(); } return name; } 

И если вам нужен полный список имен, вы можете сделать что-то вроде

 typeof (PharmacyConfigurationKeys).GetFields() .Where(x => x.GetCustomAttributes(false).Any(y => typeof(DescriptionAttribute) == y.GetType())) .Select(x => ((DescriptionAttribute)x.GetCustomAttributes(false)[0]).Description); 

Я отвечаю, чтобы настроить combo box из атрибутов enum, который был отличным.

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

Я также модифицировал код для обработки случая, когда отсутствовал атрибут

Для преимуществ следующего человека, вот мое окончательное решение

 public static class Program { static void Main(string[] args) { // display the description attribute from the enum foreach (Colour type in (Colour[])Enum.GetValues(typeof(Colour))) { Console.WriteLine(EnumExtensions.ToName(type)); } // Get the array from the description string xStr = "Yellow"; Colour thisColour = EnumExtensions.FromName(xStr); Console.ReadLine(); } public enum Colour { [Description("Colour Red")] Red = 0, [Description("Colour Green")] Green = 1, [Description("Colour Blue")] Blue = 2, Yellow = 3 } } 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(this Enum value) where T : Attribute { var type = value.GetType(); var memberInfo = type.GetMember(value.ToString()); var attributes = memberInfo[0].GetCustomAttributes(typeof(T), false); // check if no attributes have been specified. if (((Array)attributes).Length > 0) { return (T)attributes[0]; } else { return 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(); return attribute == null ? value.ToString() : attribute.Description; } ///  /// Find the enum from the description attribute. ///  ///  ///  ///  public static T FromName(this string desc) where T : struct { string attr; Boolean found = false; T result = (T)Enum.GetValues(typeof(T)).GetValue(0); foreach (object enumVal in Enum.GetValues(typeof(T))) { attr = ((Enum)enumVal).ToName(); if (attr == desc) { result = (T)enumVal; found = true; break; } } if (!found) { throw new Exception(); } return result; } } 

}

  public enum DataFilters { [Display(Name= "Equals")] Equals = 1,// Display Name and Enum Name are same [Display(Name= "Does Not Equal")] DoesNotEqual = 2, // Display Name and Enum Name are different } 

Теперь это приведет к ошибке в этом случае 1 “Равно”

 public static string GetDisplayName(this Enum enumValue) { var enumMember = enumValue.GetType().GetMember(enumValue.ToString()).First(); return enumMember.GetCustomAttribute() != null ? enumMember.GetCustomAttribute().Name : enumMember.Name; } 

поэтому, если это одно и то же имя переименования возврата, а не отображаемое имя, потому что enumMember.GetCustomAttribute () получает значение null, если displayname и имя enums одинаковы …..

Кроме того, вы можете сделать следующее:

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

И получите описание со следующим:

 string s = description[FunkyAttributesEnum.NameWithoutSpaces1]; 

На мой взгляд, это более эффективный способ делать то, что вы хотите достичь, поскольку не требуется никакого размышления.

Ребята, если это поможет, я поделюсь с вами моим решением: Определение пользовательского атрибута:

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

Теперь, потому что я нуждался в нем внутри определения HtmlHelper расширения HtmlHelper:

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

Надеюсь, поможет

Вы также можете определить значение enums, такое как Name_Without_Spaces , и когда вы хотите, чтобы описание использовало Name_Without_Spaces.ToString().Replace('_', ' ') чтобы заменить Name_Without_Spaces.ToString().Replace('_', ' ') подчеркивания пробелами.

  • Что может вызвать java.lang.reflect.InvocationTargetException?
  • Используя reflection, как вы устанавливаете значение поля struct?
  • Как перехватить вызов метода в C #?
  • Отключить reflection Java для текущего streamа
  • Как определить, реализует ли тип определенного типа общего типа
  • Почему GetType возвращает System.Int32 вместо Nullable ?
  • Как получить имя переменной с помощью отражения?
  • C # Reflection - Получить значения полей из простого classа
  • В чем разница между System.Type и System.RuntimeType в C #?
  • Используя .Net, как я могу определить, является ли тип Numeric ValueType?
  • Какая польза для тегов в Go?
  • Давайте будем гением компьютера.