Nano Hash - криптовалюты, майнинг, программирование

Перебирать элементы Enum (не только имена и не только значения)

У меня есть перечисление элементов перечисления и атрибутов описания

    public enum CourseGrades
    {
        [Description("A")]
        A = 11,
        [Description("A-")]
        AMinus = 10,
        [Description("B+")]
        BPlus = 9,
        [Description("B")]
        B = 8,
        [Description("B-")]
        BMinus = 7,
        [Description("C+")]
        CPlus = 6,
        [Description("C")]
        C = 5,
        [Description("C-")]
        CMinus = 4,
        [Description("D+")]
        DPlus = 3,
        [Description("D")]
        D = 2,
        [Description("D-")]
        DMinus = 1,
        [Description("E")]
        E = 0,
        [Description("Audit")]
        AU = -1,
        [Description("Incomplete")]
        IC = -2,
        [Description("Withdrawl")]
        WD = -3,
        [Description("Not Applicable")]
        NA = -4
    }

Моя проблема в том, что я пытаюсь составить список описаний и не могу понять, как это сделать. Все ответы, которые я видел, говорят об использовании Enum.GetNames() или Enum.GetValues(), которые я знаю, как это сделать.

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

Прямо сейчас я получаю описание, вызывая CourseGrades.A.GetDescription(), потому что у меня есть метод расширения, который обрабатывает получение атрибута описания код просмотра.

Я надеялся сделать что-то вроде

var elements = System.Enum.GetElements(CourseGrades);
var dict = new Dictionary<CourseGrades, string>();

foreach (var element in elements) {
    dict.Add(element, element.GetDescription());
}

но я начинаю думать, что что-то подобное невозможно сделать.

Я изо всех сил старался избежать грубого форсирования, делая

private Dictionary<CourseGrades, string> _courseGradesWithCaption = null;
public Dictionary < CourseGrades, string > CourseGradesWithCaptions
{
    get
    {
        if ( _courseGradesWithCaption == null )
            _courseGradesWithCaption = new Dictionary < CourseGrades, string > ()
            {
                { CourseGrades.A, CourseGrades.A.GetDescription () }
                , { CourseGrades.AMinus, CourseGrades.AMinus.GetDescription () }
                , { CourseGrades.BPlus, CourseGrades.BPlus.GetDescription () }
                // ... snip ...
            };
        return _courseGradesWithCaption;
    }
}

Я думал, что достиг чего-то, позаимствовав, как метод расширения, указанный выше, прошел через перечисление, выполнив

public static class EnumerationCaptionsBuilder
{
    public static Dictionary < T, string > BuildCaptions<T> ( T e ) where T : IConvertible
    {
        if (!(e is System.Enum)) throw new ArgumentException("e is expected to be an enumeration.");

        var type = e.GetType ();
        var values = System.Enum.GetValues ( type );
        var dict = new Dictionary<T, string> ();


        foreach ( var val in values )
        {
            if ( (int) val != e.ToInt32 ( CultureInfo.InvariantCulture ) ) continue;

            var enumElement = type.GetMember ( type.GetEnumName ( val ) ?? throw new InvalidOperationException ());

            dict.Add(enumElement, enumElement.GetDescription());
        }
    }
}

Но именно тогда я узнал, что type.GetMember возвращает объект MemberInfo, который мне не нужен.

Есть ли способ сделать то, что я хочу сделать, или я просто лаю невозможное дерево?



Ответы:


1

Я не совсем понимаю, почему ваше расширение не работает для вас (если оно есть в Enum, ваш «запрошенный» код должен работать).

Вот как я это сделал:

public static class EnumerationExtensions
{
    public static string GetDescription(this Enum value)
    {
        FieldInfo fi = value.GetType().GetField(value.ToString());

        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false);

        return attributes.Length > 0 ? attributes[0].Description : value.ToString();
    }
    public static IEnumerable<TEnum> GetEnumCollection<TEnum>(bool skipFirst = false)
    {
        var result = new List<TEnum>();
        var enums = Enum.GetValues(typeof(TEnum));
        for (int i = 0; i < enums.Length; i++)
        {
            if (skipFirst && i == 0) continue; //Some enums use "Invalid" or "Default" as first value
            TEnum e = (TEnum)enums.GetValue(i);
            result.Add(e);
        }
        return result;
    }
}

Кроме того, стоит подумать о том, зачем вам это нужно. Если это для целей отображения, возможно, вам следует использовать IValueConverter. Это позволяет вам иметь коллекцию типов перечисления, а затем довольно просто отображать описание, поскольку объект IValueConverter получает перечисление, а затем возвращает вызов расширения .Description.

В примере, который я предоставил, «skipFirst» по умолчанию имеет значение false, потому что часто, когда я делаю перечисления, я сначала ставлю недопустимое состояние (например, Default, Undefined и т. д.), чтобы гарантировать, что состояние по умолчанию недействительно (я хочу убедиться, что что-то установлено, а не использовать значение по умолчанию).

РЕДАКТИРОВАТЬ Добавление IValueConverter, который я использовал.

public class EnumerationToDescriptionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var casted = value as Enum;
        return casted?.GetDescription();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //we have no need to get from visual descirption to the enumeration at this time.
        throw new NotImplementedException();
    }
}

Затем вам просто нужно создать экземпляр конвертера как ресурса с ключом и сослаться на него.

<converters:EnumerationToDescriptionConverter x:Key="EnumerationToDescriptionConverter" />

<TextBlock Text="{Binding Converter={StaticResource EnumerationToDescriptionConverter}}"/>

В моем случае TextBlock находится внутри DataTemplate, используемого для ItemsControl, который привязан к коллекции перечислений, которые извлекаются с помощью другого метода расширения, опубликованного выше.

05.08.2019
  • Я использую его для заполнения поля со списком WPF. Не могли бы вы показать мне пример того, как сделать что-то подобное с преобразователем значений? 05.08.2019
  • В то же время его можно использовать в других частях кода для получения описания поля enum. 05.08.2019
  • Я обновил сообщение, включив в него конвертер и пример его использования. 05.08.2019
  • В конечном итоге я пытаюсь сделать это: в поле со списком в wpf">stackoverflow.com/questions/58743/, не отрицая расширение GetDescription 05.08.2019
  • Не могли бы вы показать мне полный пример с выпадающим списком? Я все еще изучаю WPF, поэтому меня немного трясет, и я хотел бы увидеть пример использования. У меня проблемы с тем, чтобы ItemsSource и шаблоны данных работали нормально. 05.08.2019
  • Я смог сделать это со следующими pastebin.com/s573m1vc и pastebin.com/BcrgtSCC 06.08.2019
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..