Как будто вы пытаетесь получить доступ к объекту, который является null
. Рассмотрим ниже пример:
TypeA objA;
. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException
, что имеет смысл.
См. Также этот пример:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
UPDATE
Первое решение было сосредоточено на получении отображаемых имен из перечисления. Код ниже должен быть точным решением для вашей проблемы.
Вы можете использовать этот вспомогательный класс для перечислений:
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>
Надеюсь, это помогает! :)
Если вы используете MVC 5.1 или верхний, это проще и понятнее: просто используйте аннотацию данных (из пространства имен 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-помощник:
@Html.EnumDropDownListFor(model => model.Color)
Чтобы получить доступ к этому атрибуту, вам нужно немного отразить:
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;
Я рекомендую обернуть этот метод в методе расширения или выполнить это в модели представления.
Один лайнер - синтаксис Fluent
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);
}
}
В какой сезон это ? Это лето
blockquote>
.NET Framework 4.5
и что вы включаете следующие пространства имен System.Net
System.ComponentModel.DataAnnotations
– Aydin Adn
29 April 2015 в 12:32
На основе ответа Aydin я бы предложил менее «дублирующую» реализацию (потому что мы могли бы легко получить Type
из самого значения Enum
, а не предоставлять его как параметр
this
должен быть допустимым (не нулевым) значением Enum. В противном случае вызов метода уже будет выполняться (который является ответственностью вызывающего кода). Это означает, что GetType()
наверняка предоставит правильный тип Enum, в котором enumvalue
наверняка будет членом. Но GetCustomAttribute может вернуть нулевое значение, поэтому я предоставил неисключительную версию метода для возврата null, когда цепочка вызовов метода имеет нулевое возвращаемое значение где-то. Благодаря!
– Bernoulli IT
6 June 2018 в 14:33
Вы можете использовать Type.GetMember Method , затем получить информацию об атрибуте с помощью отражения:
// 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 Показать значение атрибута отображения Enum?
@Html.DisplayFor(m => m.myEnum.GetDisplayName())
, который не будет работать, поскольку они ожидают, что оцениваемое выражение вы получите свойство или что-то подобное. Вы должны использовать значение голого enum, как в приведенном выше примере.
– Todd
3 October 2015 в 21:09
GetCustomAttribute<DisplayAttribute>()
, потому что для некоторых Enums этого, возможно, нет. Он возвращается к enumValue.ToString()
, если DisplayAttribute не присутствовал.
– H Dog
26 May 2016 в 16:31
List<SelectListItem>
, который был заполнен Enum со всеми индивидуальными аннотациями DisplayAttribute.Name
- это отлично работало, спасибо! public List<SelectListItem> MySelectListItem = new List<SelectListItem>(); foreach (MyEnum MyEnum in Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Where(x => x != MyEnum.Default)) { MySelectListItem.Add(new SelectListItem() { Text = MyEnum.GetDisplayName(), Value = ((int)MyEnum).ToString() }); }
– Hopper
9 June 2017 в 20:31
<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>
Основываясь на предыдущих ответах, я создал этот удобный помощник для поддержки всех свойств 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();
}
}
В дальнейшем, опираясь на ответы Айдына и Тодда, здесь приведен метод расширения, который также позволяет получить имя из файла ресурсов
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
}
Я пытался сделать это как редактирование, но он был отклонен; Я не понимаю, почему.
Вышеупомянутое выдает исключение, если вы вызываете его с помощью Enum, в котором есть сочетание пользовательских атрибутов и простых элементов, например
public enum CommentType
{
All = 1,
Rent = 2,
Insurance = 3,
[Display(Name="Service Charge")]
ServiceCharge = 4
}
So Я немного изменил код, чтобы проверить пользовательские атрибуты, прежде чем пытаться получить к ним доступ, и использовать имя, если ни один не найден.
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();
}
}
Прошу прощения за это, но я не мог использовать какие-либо другие ответы как есть, и не успел выкупить его в комментариях.
Использует синтаксис 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>();
}
Основываясь на великом ответе Тодда , который построен на большом ответе Aydin , здесь есть метод расширения 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
Если это сложное решение простой проблемы, сообщите мне, но это было исправление, которое я использовал.
.ToString
, но из stackoverflow.com/q/483794/179311 вместо этого используетсяEnum.GetName
. – bradlis7 30 December 2014 в 19:45GetDisplayValue
вы должны сначала проверитьdescriptionAttributes == null
, прежде чем пытаться получить доступ к массиву:descriptionAttributes[0]
. В противном случае вы можете создать исключение, а строка ниже, где вы проверите значение null, никогда не будет правдой. – Robert S. 31 July 2017 в 14:59