Следующее или предыдущее перечисление

Учитывая перечисление, которому присвоены значения, каков наилучший способ получить следующее или предыдущее перечисление с заданным значением. Например, рассмотрим это перечисление:

public enum TimeframeType {
    None = 0,
    [Description("1 month")]
    Now = 30,
    [Description("1-3 months")]
    Short = 90,
    [Description("3-6 months")]
    Medium = 180,
    [Description("6+ months")]
    Long = 360
}

Есть ли хороший способ создать функцию, которая бы EnumPrevious (TimeframeType.Short) возвращала TimeframeType.Now, а EnumNext (TimeframeType.Short) возвращала бы TimeframeType.Medium?

Я уже написал уродливую реализацию EnumNext, но не уверен, что это лучший способ сделать это. Я надеюсь, что кто-то уже решил эту проблему.

public static T EnumNext<T>(T value) where T : struct {
    T[] values = (T[])Enum.GetValues(typeof(T));

    int i;
    for (i = 0; i < values.Length; i++) {
        if (object.Equals(value, values[i])) {
            break;
        }
    }
    if (i >= values.Length - 1) {
        return values[values.Length - 1];
    } else {
        return values[i + 1];
    }
}

person DavGarcia    schedule 10.01.2009    source источник
comment
Это хороший пример использования неправильного инструмента для работы - отсюда и мой положительный отзыв. Спасибо за хороший вопрос. знак равно   -  person Erik Forbes    schedule 10.01.2009


Ответы (5)


Вы пытаетесь решить не ту проблему. Это слишком сложно для вычисления с помощью простого перечисления. Выполните рефакторинг перечисления до класса и используйте интерфейс сравнения.

Если этот маршрут открыт для вас, посмотрите, как это может быть реализовано классом:

public class TimeFrame: IComparable
{
   private int days;

   public int Days
   {
        set 
        {
             days = value;
        }
   }

   public int CompareTo(object other)
   {
        //see this for implementation -- http://msdn.microsoft.com/en-us/library/system.icomparable.aspx#Mtps_DropDownFilterText
   }


   public string Description
   {
       get code to return the description string , ie "1-3 months"
   }

}
person Jimmy McNulty    schedule 10.01.2009
comment
Ах, это намного лучший подход. Этот класс долгое время был перечислением, и при добавлении новых функций я пытался расширить вместо рефакторинга. Спасибо за удар по голове :) - person DavGarcia; 10.01.2009
comment
Просто хотел добавить, есть также интерфейс IComparable ‹T› для тех, кто копирует пример кода выше, который позволит вам не проверять тип CompareTo. - person DavGarcia; 13.01.2009

Перечисления в .NET на самом деле не предназначены для упорядочивания, поэтому не стоит на них полагаться. Кто-то другой позже может просто прийти и добавить значение где-то посередине, которое будет не в порядке. Таким образом, такой встроенной функции также нет. Вы можете писать свои собственные функции (аналогичные тем, что вы уже написали), но это полностью зависит от вас. Я бы также посоветовал вам выполнять сортировку самостоятельно в своем методе и не полагаться на .NET, чтобы элементы оставались «отсортированными».

Добавлено: Я также разделяю мнение о том, что вам следует выбрать другую структуру данных.

person Vilx-    schedule 10.01.2009

Насколько я знаю, для этого нет встроенного способа, и ваше решение выглядит просто шикарно - если предположить, что enum - правильная конструкция для использования здесь ...

Я действительно думаю, что вы слишком много пытаетесь сделать с перечислением. Возможно, TimeframeType должен быть классом или должен быть статический массив данных Timeframe?

(только что видел пост Джимми - похоже, у нас аналогичное мнение).

person Daniel Paull    schedule 10.01.2009

См. Вопрос Enum в C ++, например Enum в Ada, чтобы узнать, что Ада делает - и, несмотря на то, что там написано в комментариях, я не думаю, что тривиально обеспечить ту же функциональность на C, C ++ или (я думаю) на C # или Java, если эти системы не предоставляют помощь автоматически.

person Jonathan Leffler    schedule 10.01.2009

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

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

public enum TimeframeType {
    None = 0,
    [Description("1 month")]

    TimeFrameStep = 30,
    [Description("Step from previous to next")]

    Now = None + TimeFrameStep,
    [Description("1-3 months")]
    
    Short = Now + TimeFrameStep,
    [Description("3-6 months")]

    Medium = Now + TimeFrameStep,
    [Description("6+ months")]
    
    Long = Medium + TimeFrameStep,
    [Description("12 months")]
}

Затем я бы перешел от Now к Long, увеличивая инкремент на TimeFrameStep.

person hhafez    schedule 10.01.2009