Как получить отображаемое значение из перечисления в C #? [Дубликат]

Как будто вы пытаетесь получить доступ к объекту, который является null. Рассмотрим ниже пример:

TypeA objA;

. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException, что имеет смысл.

См. Также этот пример:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
153
задан dab 10 April 2015 в 00:55
поделиться

15 ответов

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>

Надеюсь, это помогает! :)

141
ответ дан ᴍᴀᴛᴛ ʙᴀᴋᴇʀ 19 August 2018 в 13:00
поделиться
  • 1
    Все ответы используют .ToString, но из stackoverflow.com/q/483794/179311 вместо этого используется Enum.GetName. – bradlis7 30 December 2014 в 19:45
  • 2
    value.GetType (). GetField (value.ToString ()) был именно тем, что я искал! – cdie 13 June 2016 в 08:07
  • 3
    Этот ответ хорош с добавлением нулевой проверки, но если вы не используете dotfuscation, ответ на stackoverflow.com/a/4412730/852806 кажется более простым. – HockeyJ 20 February 2017 в 22:00
  • 4
    В GetDisplayValue вы должны сначала проверить descriptionAttributes == null, прежде чем пытаться получить доступ к массиву: descriptionAttributes[0]. В противном случае вы можете создать исключение, а строка ниже, где вы проверите значение null, никогда не будет правдой. – Robert S. 31 July 2017 в 14:59
  • 5
    Я бы предложил изменения несовершеннолетних: public static IList & lt; T & gt; All all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all GetValues ​​(значение T). EnumHelper & л; Т & GT; to = & gt; открытый статический класс EnumHelper & lt; T & gt; где T: struct, IConvertible. Может быть, статический конструктор? static EnumHelper () {if (! typeof (T) .IsEnum) {throw new ArgumentException («T должен быть перечисленным типом»); }} – Tom 19 February 2018 в 09:58

Если вы используете 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)
23
ответ дан 1_bug 19 August 2018 в 13:00
поделиться
  • 1
    Это не работает для меня – Segmentation Fault 31 August 2016 в 12:12
  • 2
    Потому что он работает только для Dropdowns, а не где-либо еще. – Segmentation Fault 1 September 2016 в 06:47
  • 3
    Кажется, не существует в ядре .net – Lonefish 19 January 2017 в 16:40
  • 4
    .net использует Html.GetEnumSelectList (typeof (YourEnum)) @ Lonefish – Patrick Mcvay 29 March 2017 в 17:20
  • 5
    если мы хотим использовать @ Html.DisplayFor (yourEnumField), мы можем поместить Enum.cshtml в каталог DisplayTemplates (в общей папке). в этом файле нам нужно поставить всего 2 строки. первый из них: & quot; @model Enum & quot; второе: «@GetDisplayName (Модель)». метод GetDisplayName должен быть таким же, как в @Bernoulli IT answare – Developer 8 May 2017 в 00:47

Чтобы получить доступ к этому атрибуту, вам нужно немного отразить:

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;

Я рекомендую обернуть этот метод в методе расширения или выполнить это в модели представления.

3
ответ дан alexn 19 August 2018 в 13:00
поделиться

Один лайнер - синтаксис 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);
    } 
}

Выход

В какой сезон это ? Это лето

124
ответ дан Aydin Adn 19 August 2018 в 13:00
поделиться
  • 1
    Не существует определения GetCustomAttribute – Tito 29 April 2015 в 12:27
  • 2
    @Tito гарантирует, что ваш проект нацелен на .NET Framework 4.5 и что вы включаете следующие пространства имен System.Net System.ComponentModel.DataAnnotations – Aydin Adn 29 April 2015 в 12:32
  • 3
    используя System.Reflection; использование System.ComponentModel.DataAnnotations; Мне было нужно. – Sinned Lolwut 16 January 2016 в 14:32

На основе ответа Aydin я бы предложил менее «дублирующую» реализацию (потому что мы могли бы легко получить Type из самого значения Enum, а не предоставлять его как параметр

41
ответ дан Bernoulli IT 19 August 2018 в 13:00
поделиться
  • 1
    Безусловно, самый простой и легкий из всех ответов. Благодаря! – Casey Crookston 11 January 2017 в 19:56
  • 2
    Вы должны быть осторожны с .First (). Это вызовет исключение, например, если ваше имя переименования равно & quot; Equals & quot; – Vahagn Nahapetyan 5 June 2018 в 14:03
  • 3
    Я понимаю «опасность». с First (). В этом конкретном случае это не кажется проблемой. Потому что это метод расширения, где this должен быть допустимым (не нулевым) значением Enum. В противном случае вызов метода уже будет выполняться (который является ответственностью вызывающего кода). Это означает, что GetType() наверняка предоставит правильный тип Enum, в котором enumvalue наверняка будет членом. Но GetCustomAttribute может вернуть нулевое значение, поэтому я предоставил неисключительную версию метода для возврата null, когда цепочка вызовов метода имеет нулевое возвращаемое значение где-то. Благодаря! – Bernoulli IT 6 June 2018 в 14:33
  • 4
    Для второго варианта вашего кода кажется, что после GetMember не нужно использовать оператор с нулевым условием, потому что этот метод всегда возвращает массив MemberInfo и никогда не возвращает null. И для меня кажется, что лучше использовать FirstOrDefault, а не только First. Тогда использование нуль-условного оператора после FirstOrDefault будет выглядеть согласованным. – Alex34758 23 July 2018 в 10:27

Вы можете использовать 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?

101
ответ дан Community 19 August 2018 в 13:00
поделиться
  • 1
    Предположите добавить следующие пространства имен: using System; использование System.ComponentModel.DataAnnotations; используя System.Linq; используя System.Reflection; – Peter Kerr 11 March 2015 в 16:21
  • 2
    Slick, но я получаю {& quot; Шаблоны можно использовать только с доступом к полю, доступом к свойствам, индексом одномерного массива или однопараметрическими пользовательскими выражениями индексатора. & Quot;} – Casey Crookston 2 October 2015 в 14:33
  • 3
    Глядя на другие ответы SO для этого сообщения об ошибке (я незнаком с ним), кажется, что вы можете использовать это из метода хелберовского помощника (например, @Html.DisplayFor(m => m.myEnum.GetDisplayName()), который не будет работать, поскольку они ожидают, что оцениваемое выражение вы получите свойство или что-то подобное. Вы должны использовать значение голого enum, как в приведенном выше примере. – Todd 3 October 2015 в 21:09
  • 4
    Я добавил нулевую контрольную проверку к результату GetCustomAttribute<DisplayAttribute>(), потому что для некоторых Enums этого, возможно, нет. Он возвращается к enumValue.ToString(), если DisplayAttribute не присутствовал. – H Dog 26 May 2016 в 16:31
  • 5
    Я использовал это, чтобы создать 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>
6
ответ дан Dmytro 19 August 2018 в 13:00
поделиться

Основываясь на предыдущих ответах, я создал этот удобный помощник для поддержки всех свойств 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();
        }
    }
0
ответ дан Kryszal 19 August 2018 в 13:00
поделиться

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

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
}
2
ответ дан Peter Kerr 19 August 2018 в 13:00
поделиться
  • 1
    Я пытаюсь заставить это работать для моего проекта, но я получаю сообщение об ошибке с новым ресурсом ResourceManager (ресурс) .GetString (name); & quot; линия. Я задал вопрос ( stackoverflow.com/questions/31319251/… ), и меня отправили сюда. Когда я просматриваю & quot; ResourceManager (ресурс) & quot; при запуске он возвращает «Ресурсы.Enums.resource». Любая помощь будет принята с благодарностью. Спасибо! – Karinne 9 July 2015 в 14:32
  • 2
    Какое сообщение об ошибке вы получаете? – Peter Kerr 9 July 2015 в 16:28
  • 3
    Обновлен код, чтобы лучше обрабатывать значения null, когда у вас нет Display Name, установленного для некоторых значений enum - может помочь – Peter Kerr 9 July 2015 в 16:32
  • 4
    Это все еще не сработало. Я обновил свой вопрос в stackoverflow.com/questions/31319251/… с сообщением об ошибке. Спасибо за помощь! – Karinne 10 July 2015 в 11:48

Я пытался сделать это как редактирование, но он был отклонен; Я не понимаю, почему.

Вышеупомянутое выдает исключение, если вы вызываете его с помощью 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();
    }
}
0
ответ дан Red 19 August 2018 в 13:00
поделиться

Прошу прощения за это, но я не мог использовать какие-либо другие ответы как есть, и не успел выкупить его в комментариях.

Использует синтаксис 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>();
}
2
ответ дан Ruben Bartelink 19 August 2018 в 13:00
поделиться

Основываясь на великом ответе Тодда , который построен на большом ответе 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

Если это сложное решение простой проблемы, сообщите мне, но это было исправление, которое я использовал.

3
ответ дан Sinjai 19 August 2018 в 13:00
поделиться
105
ответ дан Community 31 October 2018 в 01:02
поделиться
0
ответ дан Deniz aydın 31 October 2018 в 01:02
поделиться
0
ответ дан Pavel 31 October 2018 в 01:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: