У меня есть перечисление.
public enum EventRange{ oneHour=1,oneHourThirtyMinutes
}
Теперь предположим, что за 1 час я хочу получить 1, а за час тридцать минут я хочу получить 1,5.
Как я могу добиться этого в ядре dotnet?
Перечисление — это, по сути, метка для int. Вы можете передать значение EventRange везде, где ожидается целое число. Вам даже не нужно бросать его. Вы можете использовать любой целочисленный тип в качестве базы для перечисления в качестве базы для перечисления, например enum ErrorCode : ushort { ...}
По какой причине вы не можете просто использовать для этого TimeSpan и разрешить любой временной диапазон (при условии, что это один)? При необходимости вы можете проверить, делится ли оно на определенное количество минут, если оно не должно быть слишком гранулированным. Использование enum для этого кажется бессмысленно ограничительным, даже если вы (на данный момент) решите, что у людей должен быть только ограниченный выбор длительности, чего также можно достичь, имея определенный список из них.
Почему бы не использовать это значение в виде минут вместо (половины) часов? так 60 и 90
Каково использование/цель этого перечисления? Это как-то ограничивает возможности? Будет ли словарь <string, float> работать в том же контексте, если это так?
Мой бизнес говорит, что у него будет список определенных выпадающих элементов. Поэтому я так и думал.
Я еще раз подумаю об этом. Благодарим за ваше предложение
Проще всего было бы просто получить тики временного интервала и использовать их для перечисления. Тики всегда представляют собой длинное целое число и могут представлять любую дату или временной интервал, которые вы хотите.
Если это только для раскрывающегося списка, то вам кажется, что вы должны просто создать карту, используя словарь или что-то между отображаемым значением (предположительно, строкой) и фактическим желаемым значением (предположительно, TimeSpan). Попытка сопоставить с плавающей точкой просто означает, что у вас, вероятно, будет другое преобразование позже между плавающей запятой и желаемым промежутком времени.
Технически компилятор может переинтерпретировать (не преобразовать) любой 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.
@JeroenMostert спасибо, обновлено. Но я отказался от этого довольно не стильного (int) актерского состава ^^
Получите тики для каждого временного интервала, который вы хотите представить следующим образом:
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). Это дает преимущество обслуживания, поскольку разработчикам не нужно сначала определять значение тика длительности.
Другим способом было бы создать функцию поиска
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 для времени.
Представьте себе этот ход мыслей: «Итак, нам нужно позволить пользователю выбирать между статическим набором длительностей… О, я знаю, давайте использовать для этого отражение!» К чему пришла эта профессия, если такие вещи допустимы?
Есть эта немецкая поговорка «Стрелять по воробьям из пушек», чтобы издеваться над чрезмерным решением проблем. Это решение больше похоже на постройку требушета для стрельбы из пушек по воробьям, и каждая пушка, конечно же, будет стрелять в воздухе только для галочки.
@GoodNightNerdPride — использование атрибутов со значениями enum — довольно стандартный способ разработки на C#. Особенно, когда enum взаимодействует с пользовательским интерфейсом и не используется для вычислений. Конечно, здесь немного не хватает C#, поскольку другие языки лучше связывают значения с полями перечисления, но приведенное выше решение является хорошим компромиссом между удобством использования (метод расширения) и ремонтопригодностью (значения рядом с полями).
Вы можете использовать метод преобразования, который принимает перечисление в качестве параметра и возвращает число с плавающей запятой, или использовать настраиваемые атрибуты для хранения нужной даты. Для пользовательских атрибутов смотрите документацию здесь