Как получить атрибут отображаемого имени члена перечисления с помощью кода MVC razor?
у меня есть свойство в моей модели под названием "Продвижение", что его тип-это перечисление флагов под названием "UserPromotion". Члены моего перечисления имеют атрибуты отображения, установленные следующим образом:
[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
}
теперь я хочу иметь возможность создать, скажем, ul в моем представлении, чтобы показать выбранные значения моего свойства "продвижение". Это то, что я сделал до сих пор, но проблема в том, что как я могу получить здесь имена?
<ul>
@foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion)))
{
var currentPromotion = (int)Model.JobSeeker.Promotion;
if ((currentPromotion & aPromotion) == aPromotion)
{
<li>Here I don't know how to get the display attribute of "currentPromotion".</li>
}
}
</ul>
15 ответов:
обновление
первое решение было сосредоточено на получении отображаемых имен из перечисления. Приведенный ниже код должен быть точным решением для вашей проблемы.
Вы можете использовать этот вспомогательный класс для перечислений:
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; public static class EnumHelper<T> { public static IList<T> GetValues(Enum value) { var enumValues = new List<T>(); 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<string> GetNames(Enum value) { return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList(); } public static IList<string> 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(); } }и затем вы можете использовать его в свой вид следующим образом:
<ul> @foreach (var value in @EnumHelper<UserPromotion>.GetValues(UserPromotion.None)) { if (value == Model.JobSeeker.Promotion) { var description = EnumHelper<UserPromotion>.GetDisplayValue(value); <li>@Html.DisplayFor(e => description )</li> } } </ul>надеюсь, что это помогает! :)
один лайнер-свободный синтаксис
public static class Extensions { /// <summary> /// A generic extension method that aids in reflecting /// and retrieving any attribute that is applied to an `Enum`. /// </summary> public static TAttribute GetAttribute<TAttribute>(this Enum enumValue) where TAttribute : Attribute { return enumValue.GetType() .GetMember(enumValue.ToString()) .First() .GetCustomAttribute<TAttribute>(); } }
пример
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<DisplayAttribute>(); Console.WriteLine("Which season is it?"); Console.WriteLine (seasonDisplayName.Name); } }
выход
какой сейчас сезон?
Сейчас лето
дом на отличный ответ Айдына, вот метод расширения, который не требует никаких параметров типа.
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<DisplayAttribute>() .GetName(); } }Примечание: GetName () следует использовать вместо свойства Name. Это гарантирует, что локализованная строка будет возвращена при использовании свойства атрибута ResourceType.
пример
чтобы использовать его, просто ссылайтесь на значение перечисления в вашем вид.
@{ UserPromotion promo = UserPromotion.SendJobOffersByMail; } Promotion: @promo.GetDisplayName()выход
Продвижение: Отправить Предложения О Работе По Почте
на основе ответ Айдына Я бы предложил менее "двуличную" реализацию (потому что мы могли бы легко получить
TypeСEnumсамо значение, а не предоставление его в качестве параметра:public static string GetDisplayName(this Enum enumValue) { return enumValue.GetType().GetMember(enumValue.ToString()) .First() .GetCustomAttribute<DisplayAttribute>() .Name; }EDIT (на основе комментария @Vahagn Nahapetyan)
public static string GetDisplayName(this Enum enumValue) { return enumValue.GetType()? .GetMember(enumValue.ToString())? .First()? .GetCustomAttribute<DisplayAttribute>()? .Name; }теперь мы можем использовать его очень чистым, таким образом:
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();что приводит к
"Мечта"
Если вы используете MVC 5.1 или upper, есть более простой и понятный способ: просто используйте аннотацию данных (от
System.ComponentModel.DataAnnotationsпространство имен), как показано ниже:public enum Color { [Display(Name = "Dark red")] DarkRed, [Display(Name = "Very dark red")] VeryDarkRed, [Display(Name = "Red or just black?")] ReallyDarkRed }и в виду, просто поместите его в правильный HTML helper:
@Html.EnumDropDownListFor(model => model.Color)
вы могли бы использовать тип.Метод GetMember, потом получить информацию об атрибуте С помощью отражения:
// 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;здесь было несколько подобных сообщений:
получение атрибутов значения Enum
как сделать MVC3 DisplayFor показать значение атрибута отображения перечисления?
<ul> @foreach (int aPromotion in @Enum.GetValues(typeof(UserPromotion))) { var currentPromotion = (int)Model.JobSeeker.Promotion; if ((currentPromotion & aPromotion) == aPromotion) { <li>@Html.DisplayFor(e => currentPromotion)</li> } } </ul>
вам нужно использовать немного отражения для доступа к этому атрибуту:
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;Я рекомендую обернуть этот метод в метод расширения или выполнить это в модели представления.
дом на отличный ответ Тодда, который построен на отличный ответ Айдына здесь generic метод расширения, который не требует никаких параметров типа.
/// <summary> /// Gets human-readable version of enum. /// </summary> /// <returns>DisplayAttribute.Name property of given enum.</returns> public static string GetDisplayName<T>(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<DisplayAttribute>(); string displayName = displayAttribute?.GetName(); return displayName ?? enumValue.ToString(); }мне это нужно для моего проекта, потому что что-то вроде ниже код, где не каждый член перечисления, имеет
DisplayAttribute, не работает с решением Тодда: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Если это сложное решение для простой проблемы, пожалуйста, дайте мне знать, но это исправить я использовал.
основываясь далее на ответах Айдина и Тодда, вот метод расширения, который также позволяет получить имя из файла ресурсов
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<DisplayAttribute>(); } 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); } }и использовать его как
public enum Season { [Display(ResourceType = typeof(Resource), Name = Season_Summer")] Summer }
Мне жаль это делать, но я не мог использовать ни один из других ответов, как есть, и у меня нет времени, чтобы вытащить его в комментариях.
использует синтаксис 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<DisplayAttribute>(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<DisplayAttribute>()?.GetName(); static TAttribute GetEnumMemberAttribute<TAttribute>(this Enum value) where TAttribute : Attribute => value.GetType().GetEnumMemberAttribute<TAttribute>(value.ToString()); static TAttribute GetEnumMemberAttribute<TAttribute>(this Type enumType, string enumMemberName) where TAttribute : Attribute => enumType.GetMember(enumMemberName).Single().GetCustomAttribute<TAttribute>(); }
на основе предыдущих ответов я создал этот удобный помощник для поддержки всех свойств DisplayAttribute в удобном для чтения виде:
public static class EnumExtensions { public static DisplayAttributeValues GetDisplayAttributeValues(this Enum enumValue) { var displayAttribute = enumValue.GetType().GetMember(enumValue.ToString()).First().GetCustomAttribute<DisplayAttribute>(); 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(); } }
Я попытался сделать это как редактирование, но оно было отклонено; я не могу понять, почему.
выше будет выдано исключение, если вы вызываете его с перечислением, которое имеет сочетание пользовательских атрибутов и простых элементов, например
public enum CommentType { All = 1, Rent = 2, Insurance = 3, [Display(Name="Service Charge")] ServiceCharge = 4 }поэтому я немного изменил код, чтобы проверить пользовательские атрибуты, прежде чем пытаться получить к ним доступ, и использовать имя, если они не найдены.
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reflection; public static class EnumHelper<T> { public static IList<T> GetValues(Enum value) { var enumValues = new List<T>(); 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<string> GetNames(Enum value) { return value.GetType().GetFields(BindingFlags.Static | BindingFlags.Public).Select(fi => fi.Name).ToList(); } public static IList<string> 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(); } }
С Ядром 2.1,
public static string GetDisplayName(Enum enumValue) { return enumValue.GetType()? .GetMember(enumValue.ToString())?[0]? .GetCustomAttribute<DisplayAttribute>()? .Name; }
Я хочу внести свой вклад в расширение перечисления GetDisplayName, зависящее от культуры. Надеюсь, что это будет полезно для тех, кто гуглит этот ответ, как я ранее:
"стандарт", так как Айдын АдН и Тодд отметил:
public static string GetDisplayName(this Enum enumValue) { return enumValue .GetType() .GetMember(enumValue.ToString()) .First() .GetCustomAttribute<DisplayAttribute>() .GetName(); }"культура-зависимых" путь:
public static string GetDisplayName(this Enum enumValue, CultureInfo ci) { var displayAttr = enumValue .GetType() .GetMember(enumValue.ToString()) .First() .GetCustomAttribute<DisplayAttribute>(); var resMan = displayAttr.ResourceType?.GetProperty(@"ResourceManager", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).GetValue(null, null) as ResourceManager; return resMan?.GetString(displayAttr.Name, ci) ?? displayAttr.GetName(); }
Comments