Obtener atributos del valor de Enum

Me gustaría saber si es posible obtener atributos de los valores enum y no de la enumeración en sí misma. Por ejemplo, supongamos que tengo la siguiente enumeración:

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

Lo que quiero es darle el tipo de enumeración, producir 2 tuplas de valor de cadena enum y su descripción.

El valor fue fácil:

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

¿Pero cómo obtengo el valor del atributo de descripción para rellenar Tuple.Desc? Puedo pensar cómo hacerlo si el Atributo pertenece a la enumeración en sí, pero no sé cómo obtenerlo del valor de la enumeración.

Esto debería hacer lo que necesites.

 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; 

Este fragmento de código debería darle un pequeño y agradable método de extensión en cualquier enumeración que le permita recuperar un atributo genérico. Creo que es diferente a la función lambda anterior porque es más fácil de usar y leve: solo debe pasar el tipo genérico.

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

Esta es una implementación genérica usando un lambda para la selección

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

Llámalo así:

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

He combinado algunas de las respuestas aquí para crear una solución un poco más extensible. Lo proporciono por si acaso es útil para cualquier otra persona en el futuro. Publicación original aquí .

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

Esta solución crea un par de métodos de extensión en Enum. El primero le permite usar la reflexión para recuperar cualquier atributo asociado con su valor. El segundo específicamente llamadas recupera la DescriptionAttribute y devuelve su valor de Description .

Como ejemplo, considere usar el atributo DescriptionAttribute de 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 } 

Para usar el método de extensión anterior, ahora simplemente llame a lo siguiente:

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

o

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

Además de la respuesta de AdamCrawford , he creado además un método de extensión más especializado que se alimenta de él para obtener la descripción.

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

por lo tanto, para obtener la descripción, puede usar el método de extensión original como

 string desc = myEnumVariable.GetAttributeOfType().Description 

o simplemente puede llamar al método de extensión aquí como:

 string desc = myEnumVariable.GetAttributeDescription(); 

Lo cual debería hacer que tu código sea un poco más legible.

Fluido un trazador de líneas …

Aquí estoy usando DisplayAttribute que contiene las propiedades de Name y Description .

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

Ejemplo

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

Salida

 Name: Sea cruise Description: Cruising on a dinghy 

Aquí hay un código para obtener información de un atributo de visualización. Utiliza un método genérico para recuperar el atributo. Si no se encuentra el atributo, convierte el valor enum a una cadena con pascal / camel case convertido a mayúscula (código obtenido aquí )

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

Y este es el método de extensión para cadenas para convertir a mayúsculas y minúsculas:

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

Obtén el diccionario de enum.

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

Ahora llama esto como …

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

Método 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 } 

Implementé este método de extensión para obtener la descripción de los valores enum. Funciona para todo tipo de enumeraciones.

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

Aquí está la versión .NET Core de la respuesta de AdamCrawford, utilizando 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]; } } 

Agregando mi solución para Net Framework y NetCore.

Usé esto para mi implementación de 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"; } } 

Esto no funciona para NetCore, así que lo modifiqué para hacer esto:

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

Ejemplo de enumeración:

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

Uso de muestra para cualquier agregado estático:

 var myDescription = myEnum.Description(); 

Aprovechando algunas de las características más nuevas del lenguaje C #, puede reducir el número de líneas:

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

Este método de extensión obtendrá una representación de cadena de un valor enum usando su XmlEnumAttribute. Si no está presente XmlEnumAttribute, vuelve a 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; } 

Y si quieres la lista completa de nombres, puedes hacer algo como

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

Yo esta respuesta para configurar un cuadro combinado de atributos enum, que fue genial.

Luego tuve que codificar el reverso para poder obtener la selección del cuadro y devolver la enumeración en el tipo correcto.

También modifiqué el código para manejar el caso donde faltaba un atributo

Para los beneficios de la siguiente persona, esta es mi solución final

 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 } 

Ahora producirá un error en este caso 1 “Igual”

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

así que si es el mismo nombre enum de devolución en lugar de mostrar nombre porque enumMember.GetCustomAttribute () obtiene nulo si displayname y enum name son los mismos …..

Alternativamente, podrías hacer lo siguiente:

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

Y obtenga la descripción con lo siguiente:

 string s = description[FunkyAttributesEnum.NameWithoutSpaces1]; 

En mi opinión, esta es una forma más eficiente de hacer lo que quiere lograr, ya que no se necesita reflexión.

Chicos si me ayuda, les compartiré mi solución: Definición de atributo personalizado:

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

Ahora porque lo necesitaba dentro de la definición HtmlHelper de 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"); } } 

Espero eso ayude

También puede definir un valor enum como Name_Without_Spaces , y cuando desee una descripción, use Name_Without_Spaces.ToString().Replace('_', ' ') para reemplazar los caracteres de subrayado por espacios.