Сопоставить enum со значением с плавающей запятой

У меня есть перечисление.

public enum EventRange{ oneHour=1,oneHourThirtyMinutes
}

Теперь предположим, что за 1 час я хочу получить 1, а за час тридцать минут я хочу получить 1,5.

Как я могу добиться этого в ядре dotnet?

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

Franck 20.02.2023 16:39

Перечисление — это, по сути, метка для int. Вы можете передать значение EventRange везде, где ожидается целое число. Вам даже не нужно бросать его. Вы можете использовать любой целочисленный тип в качестве базы для перечисления в качестве базы для перечисления, например enum ErrorCode : ushort { ...}

Panagiotis Kanavos 20.02.2023 16:40

По какой причине вы не можете просто использовать для этого TimeSpan и разрешить любой временной диапазон (при условии, что это один)? При необходимости вы можете проверить, делится ли оно на определенное количество минут, если оно не должно быть слишком гранулированным. Использование enum для этого кажется бессмысленно ограничительным, даже если вы (на данный момент) решите, что у людей должен быть только ограниченный выбор длительности, чего также можно достичь, имея определенный список из них.

Jeroen Mostert 20.02.2023 16:42

Почему бы не использовать это значение в виде минут вместо (половины) часов? так 60 и 90

Hans Kesting 20.02.2023 16:45

Каково использование/цель этого перечисления? Это как-то ограничивает возможности? Будет ли словарь <string, float> работать в том же контексте, если это так?

sr28 20.02.2023 16:46

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

Saidur Rahman 20.02.2023 16:46

Я еще раз подумаю об этом. Благодарим за ваше предложение

Saidur Rahman 20.02.2023 16:47

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

Max 20.02.2023 16:58

Если это только для раскрывающегося списка, то вам кажется, что вы должны просто создать карту, используя словарь или что-то между отображаемым значением (предположительно, строкой) и фактическим желаемым значением (предположительно, TimeSpan). Попытка сопоставить с плавающей точкой просто означает, что у вас, вероятно, будет другое преобразование позже между плавающей запятой и желаемым промежутком времени.

sr28 20.02.2023 17:19
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
Запуск PHP на IIS без использования программы установки веб-платформы
Запуск PHP на IIS без использования программы установки веб-платформы
Установщик веб-платформы, предлагаемый компанией Microsoft, перестанет работать 31 декабря 2022 года. Его закрытие привело к тому, что мы не можем...
Оптимизация React Context шаг за шагом в 4 примерах
Оптимизация React Context шаг за шагом в 4 примерах
При использовании компонентов React в сочетании с Context вы можете оптимизировать рендеринг, обернув ваш компонент React в React.memo сразу после...
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
Настройка шаблона Metronic с помощью Webpack и Gulp
Настройка шаблона Metronic с помощью Webpack и Gulp
Я пишу эту статью, чтобы поделиться тем, как настроить макет Metronic с помощью Sass, поскольку Metronic предоставляет так много документации, и они...
0
9
75
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Технически компилятор может переинтерпретировать (не преобразовать) любой float как int вот так:

float f = 1.5f;
int i = *(int*)&f; // i = 1069547520

Это, конечно, также работает и наоборот, и даже для значений перечисления (которые на самом деле просто ints):

public enum EventRange {
    OneHour = 1065353216,
    OneHourThirtyMinutes = 1069547520
}

var e = EventRange.OneHourThirtyMinutes;
float f = *(float*)&e; // f = 1.5f

// nicer notation as mentioned in the comments
f = Unsafe.As<EventRange, float>(ref e);

Однако ваши друзья и семья будут сторониться вас за это. Количество отрицательных голосов, которые получит этот ответ, должно произвести на вас впечатление.

Меньше всего вы могли бы пойти на очки стиля: int e = (int) EventRange.OneHourThirtyMinutes; float f = Unsafe.As<int, float>(ref e);. Конечно, это остается злоупотреблением enum.

Jeroen Mostert 20.02.2023 17:18

@JeroenMostert спасибо, обновлено. Но я отказался от этого довольно не стильного (int) актерского состава ^^

Good Night Nerd Pride 20.02.2023 17:23

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

System.Diagnostics.Debug.WriteLine(new TimeSpan(1, 30, 0).Ticks);

Теперь вы можете назначить его своему перечислению:

enum EventRange : long 
{
    oneHourThirtyMinutes = 54000000000,
/* ... */
}

И конвертировать обратно так

TimeSpan ts = new TimeSpan((long)EventRange.oneHourThirtyMinutes);

Похоже, что OP требуется разрешение не более 1 минуты (вероятно, больше 30 минут). Поэтому, если вы измените значения enum int на 60, 90 и т. д., вы можете использовать TimeSpan.FromMinutes((int)enumValue). Это дает преимущество обслуживания, поскольку разработчикам не нужно сначала определять значение тика длительности.

Good Night Nerd Pride 22.02.2023 11:29
Ответ принят как подходящий

Другим способом было бы создать функцию поиска

public enum EventRange
{
    zero,
    oneHour, 
    oneHourThirtyMinutes,
}

public static class Extensions
{
    public static float GetHours(this EventRange range)
    {
        switch (range)
        {
            case EventRange.zero:
                return 0f;
            case EventRange.oneHour:
                return 1f;
            case EventRange.oneHourThirtyMinutes:
                return 1.5f;
            default:
                throw new NotSupportedException($"{range} value not supported.");
        }
    }
}

static class Program
{
    static void Main(string[] args)
    {
        float time = EventRange.oneHourThirtyMinutes.GetHours();
    }
}

И альтернативой, которая лучше подходит для обслуживания кода, является создание настраиваемого атрибута для применения значений перечисления, аналогично тому, как работает DescriptionAttribute().

public class EventTimeAttribute : Attribute
{
    public EventTimeAttribute(float time) : base()
    {
        Time = time;
    }

    public float Time { get; }
}

public enum EventRange
{
    [EventTime(0)] zero,
    [EventTime(1f)] oneHour, 
    [EventTime(1.5f)] oneHourThirtyMinutes,
}

public static class Extensions
{
    public static float GetHours(this EventRange range)
    {
        FieldInfo field = typeof(EventRange).GetField(range.ToString());
        if (field != null)
        {
            var attribute = field.GetCustomAttribute<EventTimeAttribute>();
            if (attribute != null)
            {
                return attribute.Time;
            }
        }
        throw new NotSupportedException($"{range} value not supported.");
    }
}

static class Program
{
    static void Main(string[] args)
    {
        float time = EventRange.oneHourThirtyMinutes.GetHours();
    }
}

Этот метод можно легко расширить для поддержки TimeSpan вместо float для времени.

Представьте себе этот ход мыслей: «Итак, нам нужно позволить пользователю выбирать между статическим набором длительностей… О, я знаю, давайте использовать для этого отражение!» К чему пришла эта профессия, если такие вещи допустимы?

Good Night Nerd Pride 22.02.2023 09:24

Есть эта немецкая поговорка «Стрелять по воробьям из пушек», чтобы издеваться над чрезмерным решением проблем. Это решение больше похоже на постройку требушета для стрельбы из пушек по воробьям, и каждая пушка, конечно же, будет стрелять в воздухе только для галочки.

Good Night Nerd Pride 22.02.2023 09:35

@GoodNightNerdPride — использование атрибутов со значениями enum — довольно стандартный способ разработки на C#. Особенно, когда enum взаимодействует с пользовательским интерфейсом и не используется для вычислений. Конечно, здесь немного не хватает C#, поскольку другие языки лучше связывают значения с полями перечисления, но приведенное выше решение является хорошим компромиссом между удобством использования (метод расширения) и ремонтопригодностью (значения рядом с полями).

John Alexiou 22.02.2023 15:06

Другие вопросы по теме