¿Cómo obtener el atributo de nombre de visualización de un miembro de Enum a través del código de afeitado MVC?

Tengo una propiedad en mi modelo llamada “Promoción” que su tipo es una enumeración de marca llamada “UserPromotion”. Los miembros de mi enumeración tienen atributos de visualización establecidos de la siguiente manera:

[Flags] public enum UserPromotion { None = 0x0, [Display(Name = "Send Job Offers By Mail")] SendJobOffersByMail = 0x1, [Display(Name = "Send Job Offers By Sms")] SendJobOffersBySms = 0x2, [Display(Name = "Send Other Stuff By Sms")] SendPromotionalBySms = 0x4, [Display(Name = "Send Other Stuff By Mail")] SendPromotionalByMail = 0x8 } 

Ahora quiero poder crear, por ejemplo, una ul en mi vista para mostrar los valores seleccionados de mi propiedad “Promocionar”. Esto es lo que he hecho hasta ahora, pero el problema es que ¿cómo puedo obtener los nombres para mostrar aquí?

 
    @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion))) { var currentPromotion = (int)Model.JobSeeker.Promotion; if ((currentPromotion & aPromotion) == aPromotion) {
  • Here I don't know how to get the display attribute of "currentPromotion".
  • } }

ACTUALIZAR

La primera solución se centró en obtener nombres para mostrar de enum. El siguiente código debe ser la solución exacta para su problema.

Puedes usar esta clase de ayuda para enumeraciones:

 using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; public static class EnumHelper { public static IList GetValues(Enum value) { var enumValues = new List(); foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public)) { enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false)); } return enumValues; } public static T Parse(string value) { return (T)Enum.Parse(typeof(T), value, true); } public static IList GetNames(Enum value) { return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList(); } public static IList GetDisplayValues(Enum value) { return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList(); } private static string lookupResource(Type resourceManagerProvider, string resourceKey) { foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager)) { System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null); return resourceManager.GetString(resourceKey); } } return resourceKey; // Fallback with the key name } public static string GetDisplayValue(T value) { var fieldInfo = value.GetType().GetField(value.ToString()); var descriptionAttributes = fieldInfo.GetCustomAttributes( typeof(DisplayAttribute), false) as DisplayAttribute[]; if (descriptionAttributes[0].ResourceType != null) return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name); if (descriptionAttributes == null) return string.Empty; return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString(); } } 

Y luego puede usarlo en su vista de la siguiente manera:

 
    @foreach (var value in @EnumHelper.GetValues(UserPromotion.None)) { if (value == Model.JobSeeker.Promotion) { var description = EnumHelper.GetDisplayValue(value);
  • @Html.DisplayFor(e => description )
  • } }

¡Espero eso ayude! 🙂

Un trazador de líneas – syntax fluida

 public static class Extensions { ///  /// A generic extension method that aids in reflecting /// and retrieving any attribute that is applied to an `Enum`. ///  public static TAttribute GetAttribute(this Enum enumValue) where TAttribute : Attribute { return enumValue.GetType() .GetMember(enumValue.ToString()) .First() .GetCustomAttribute(); } } 

Ejemplo

 public enum Season { [Display(Name = "It's autumn")] Autumn, [Display(Name = "It's winter")] Winter, [Display(Name = "It's spring")] Spring, [Display(Name = "It's summer")] Summer } public class Foo { public Season Season = Season.Summer; public void DisplayName() { var seasonDisplayName = Season.GetAttribute(); Console.WriteLine("Which season is it?"); Console.WriteLine (seasonDisplayName.Name); } } 

Salida

¿Qué temporada es?
Es verano

Sobre la base de la gran respuesta de Aydin , este es un método de extensión que no requiere ningún tipo de parámetros.

 using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; public static class EnumExtensions { public static string GetDisplayName(this Enum enumValue) { return enumValue.GetType() .GetMember(enumValue.ToString()) .First() .GetCustomAttribute() .GetName(); } } 

NOTA: GetName () debe usarse en lugar de la propiedad Name. Esto garantiza que se devolverá la cadena localizada si se usa la propiedad de atributo ResourceType.

Ejemplo

Para usarlo, simplemente haga referencia al valor enum en su vista.

 @{ UserPromotion promo = UserPromotion.SendJobOffersByMail; } Promotion: @promo.GetDisplayName() 

Salida

Promoción: envíe ofertas de trabajo por correo

Basándome en la respuesta de Aydin, sugeriría una implementación menos “duplicada” (porque podríamos obtener fácilmente el Type del valor de Enum , en lugar de proporcionarlo como un parámetro 😉:

 public static string GetDisplayName(this Enum enumValue) { return enumValue.GetType().GetMember(enumValue.ToString()) .First() .GetCustomAttribute() .Name; } 

EDITAR (basado en el comentario de @Vahagn Nahapetyan)

 public static string GetDisplayName(this Enum enumValue) { return enumValue.GetType()? .GetMember(enumValue.ToString())? .First()? .GetCustomAttribute()? .Name; } 

Ahora podemos usarlo muy limpio de esta manera:

 public enum Season { [Display(Name = "The Autumn")] Autumn, [Display(Name = "The Weather")] Winter, [Display(Name = "The Tease")] Spring, [Display(Name = "The Dream")] Summer } Season.Summer.GetDisplayName(); 

Lo que resulta en

“El sueño”

Si está utilizando MVC 5.1 o superior, hay una manera más simple y clara: simplemente use la anotación de datos (del espacio de nombres System.ComponentModel.DataAnnotations ) como se muestra a continuación:

 public enum Color { [Display(Name = "Dark red")] DarkRed, [Display(Name = "Very dark red")] VeryDarkRed, [Display(Name = "Red or just black?")] ReallyDarkRed } 

Y a la vista, simplemente colóquelo en el asistente de html adecuado:

 @Html.EnumDropDownListFor(model => model.Color) 

Podría usar el método Type.GetMember , luego obtener la información del atributo usando reflection:

 // display attribute of "currentPromotion" var type = typeof(UserPromotion); var memberInfo = type.GetMember(currentPromotion.ToString()); var attributes = memberInfo[0].GetCustomAttributes(typeof(DisplayAttribute), false); var description = ((DisplayAttribute)attributes[0]).Name; 

Hubo algunos mensajes similares aquí:

Obtener atributos del valor de Enum

¿Cómo hacer que MVC3 DisplayFor muestre el valor de un Aum Display-Attribute?

 
    @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion))) { var currentPromotion = (int)Model.JobSeeker.Promotion; if ((currentPromotion & aPromotion) == aPromotion) {
  • @Html.DisplayFor(e => currentPromotion)
  • } }

Necesitas usar un poco de reflexión para acceder a ese atributo:

 var type = typeof(UserPromotion); var member = type.GetMember(Model.JobSeeker.Promotion.ToString()); var attributes = member[0].GetCustomAttributes(typeof(DisplayAttribute), false); var name = ((DisplayAttribute)attributes[0]).Name; 

Recomiendo envolver este método en un método de extensión o realizar esto en un modelo de vista.

Sobre la base de la gran respuesta de Todd que se basa en la gran respuesta de Aydin , este es un método de extensión genérico que no requiere ningún tipo de parámetros.

 ///  /// Gets human-readable version of enum. ///  /// DisplayAttribute.Name property of given enum. public static string GetDisplayName(this T enumValue) where T : IComparable, IFormattable, IConvertible { if (!typeof(T).IsEnum) throw new ArgumentException("Argument must be of type Enum"); DisplayAttribute displayAttribute = enumValue.GetType() .GetMember(enumValue.ToString()) .First() .GetCustomAttribute(); string displayName = displayAttribute?.GetName(); return displayName ?? enumValue.ToString(); } 

Necesitaba esto para mi proyecto porque algo como el siguiente código, donde no todos los miembros de la enumeración tienen un DisplayAttribute , no funciona con la solución de Todd:

 public class MyClass { public enum MyEnum { [Display(Name="ONE")] One, // No DisplayAttribute Two } public void UseMyEnum() { MyEnum foo = MyEnum.One; MyEnum bar = MyEnum.Two; Console.WriteLine(foo.GetDisplayName()); Console.WriteLine(bar.GetDisplayName()); } } // Output: // // ONE // Two 

Si esta es una solución complicada a un problema simple, hágamelo saber, pero esta fue la solución que utilicé.

Continuando con las respuestas de Aydin y Todd, este es un método de extensión que también le permite obtener el nombre de un archivo de recursos.

 using AppResources; using System; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; using System.Resources; public static class EnumExtensions { public static string GetDisplayName(this Enum enumValue) { var enumMember= enumValue.GetType() .GetMember(enumValue.ToString()); DisplayAttribute displayAttrib = null; if (enumMember.Any()) { displayAttrib = enumMember .First() .GetCustomAttribute(); } string name = null; Type resource = null; if (displayAttrib != null) { name = displayAttrib.Name; resource = displayAttrib.ResourceType; } return String.IsNullOrEmpty(name) ? enumValue.ToString() : resource == null ? name : new ResourceManager(resource).GetString(name); } } 

y usarlo como

 public enum Season { [Display(ResourceType = typeof(Resource), Name = Season_Summer")] Summer } 

Lamento hacer esto, pero no pude usar ninguna de las otras respuestas tal como están y no tengo tiempo para hablar en los comentarios.

Utiliza la syntax C # 6.

 static class EnumExtensions { /// returns the localized Name, if a [Display(Name="Localised Name")] attribute is applied to the enum member /// returns null if there isnt an attribute public static string DisplayNameOrEnumName(this Enum value) // => value.DisplayNameOrDefault() ?? value.ToString() { // More efficient form of ^ based on http://stackoverflow.com/a/17034624/11635 var enumType = value.GetType(); var enumMemberName = Enum.GetName(enumType, value); return enumType .GetEnumMemberAttribute(enumMemberName) ?.GetName() // Potentially localized ?? enumMemberName; // Or fall back to the enum name } /// returns the localized Name, if a [Display] attribute is applied to the enum member /// returns null if there is no attribute public static string DisplayNameOrDefault(this Enum value) => value.GetEnumMemberAttribute()?.GetName(); static TAttribute GetEnumMemberAttribute(this Enum value) where TAttribute : Attribute => value.GetType().GetEnumMemberAttribute(value.ToString()); static TAttribute GetEnumMemberAttribute(this Type enumType, string enumMemberName) where TAttribute : Attribute => enumType.GetMember(enumMemberName).Single().GetCustomAttribute(); } 

Basado en las respuestas anteriores, creé este cómodo helper para admitir todas las propiedades de DisplayAttribute de una manera legible:

 public static class EnumExtensions { public static DisplayAttributeValues GetDisplayAttributeValues(this Enum enumValue) { var displayAttribute = enumValue.GetType().GetMember(enumValue.ToString()).First().GetCustomAttribute(); return new DisplayAttributeValues(enumValue, displayAttribute); } public sealed class DisplayAttributeValues { private readonly Enum enumValue; private readonly DisplayAttribute displayAttribute; public DisplayAttributeValues(Enum enumValue, DisplayAttribute displayAttribute) { this.enumValue = enumValue; this.displayAttribute = displayAttribute; } public bool? AutoGenerateField => this.displayAttribute?.GetAutoGenerateField(); public bool? AutoGenerateFilter => this.displayAttribute?.GetAutoGenerateFilter(); public int? Order => this.displayAttribute?.GetOrder(); public string Description => this.displayAttribute != null ? this.displayAttribute.GetDescription() : string.Empty; public string GroupName => this.displayAttribute != null ? this.displayAttribute.GetGroupName() : string.Empty; public string Name => this.displayAttribute != null ? this.displayAttribute.GetName() : this.enumValue.ToString(); public string Prompt => this.displayAttribute != null ? this.displayAttribute.GetPrompt() : string.Empty; public string ShortName => this.displayAttribute != null ? this.displayAttribute.GetShortName() : this.enumValue.ToString(); } } 

Intenté hacer esto como una edición pero fue rechazado; No puedo ver por qué.

Lo anterior arrojará una excepción si lo llama con un Enum que tiene una combinación de atributos personalizados y elementos simples, por ejemplo

 public enum CommentType { All = 1, Rent = 2, Insurance = 3, [Display(Name="Service Charge")] ServiceCharge = 4 } 

Así que modifiqué ligeramente el código para verificar los atributos personalizados antes de intentar acceder a ellos, y uso el nombre si no se encuentra ninguno.

 using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; public static class EnumHelper { public static IList GetValues(Enum value) { var enumValues = new List(); foreach (FieldInfo fi in value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public)) { enumValues.Add((T)Enum.Parse(value.GetType(), fi.Name, false)); } return enumValues; } public static T Parse(string value) { return (T)Enum.Parse(typeof(T), value, true); } public static IList GetNames(Enum value) { return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList(); } public static IList GetDisplayValues(Enum value) { return GetNames(value).Select(obj => GetDisplayValue(Parse(obj))).ToList(); } private static string lookupResource(Type resourceManagerProvider, string resourceKey) { foreach (PropertyInfo staticProperty in resourceManagerProvider.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { if (staticProperty.PropertyType == typeof(System.Resources.ResourceManager)) { System.Resources.ResourceManager resourceManager = (System.Resources.ResourceManager)staticProperty.GetValue(null, null); return resourceManager.GetString(resourceKey); } } return resourceKey; // Fallback with the key name } public static string GetDisplayValue(T value) { var fieldInfo = value.GetType().GetField(value.ToString()); var descriptionAttributes = fieldInfo.GetCustomAttributes( typeof(DisplayAttribute), false) as DisplayAttribute[]; if (descriptionAttributes.Any() && descriptionAttributes[0].ResourceType != null) return lookupResource(descriptionAttributes[0].ResourceType, descriptionAttributes[0].Name); if (descriptionAttributes == null) return string.Empty; return (descriptionAttributes.Length > 0) ? descriptionAttributes[0].Name : value.ToString(); } } 

Con Core 2.1,

 public static string GetDisplayName(Enum enumValue) { return enumValue.GetType()? .GetMember(enumValue.ToString())?[0]? .GetCustomAttribute()? .Name; }