Когда использовать перечисления, и когда заменить их классом со статическими участниками?

Мне что следующее (демонстрационное) перечисление недавно пришло в голову...

enum Color
{
    Red,
    Green,
    Yellow,
    Blue
}

... мог быть заменен по-видимому большим количеством безопасного с точки зрения типов класса:

class Color
{
    private Color() { }

    public static readonly Color   Red      = new Color();
    public static readonly Color   Green    = new Color();
    public static readonly Color   Yellow   = new Color();
    public static readonly Color   Blue     = new Color();
}

С "безопасным с точки зрения типов" я подразумеваю, что следующее утверждение работало бы если Color было перечисление, но не если Color был вышеупомянутый класс:

var nonsenseColor = (Color)17;    // works if Color is an enum

Два вопроса:

1) Существует ли широко принятое имя к этому шаблону (заменяющий перечисление безопасным с точки зрения типов классом)?

2) В которых случаях нужно использовать перечисления, и когда класс был бы более соответствующим?

33
задан 3 revs 2 May 2012 в 19:52
поделиться

6 ответов

Enums отлично подходит для легкой состояния информации. Например, ваш цветной сигнал (исключая синий) был бы хорошим для запроса состояния светофора. Истинный цвет вместе со всей концепцией цвета и всем его багажом (альфа, цветное пространство и т. Д.) Не имеет значения, просто какое состояние находится в свете. Кроме того, изменяя свой канал немного, чтобы представлять состояние светофора :

[Flags()]
public enum LightColors
{
    unknown = 0,
    red = 1,
    yellow = 2,
    green = 4,
    green_arrow = 8
}

Состояние текущего света может быть установлено как:

LightColors c = LightColors.red | LightColors.green_arrow;

и запрашивается как:

if ((c & LightColors.red) == LightColors.red)
{
    //Don't drive
}
else if ((c & LightColors.green_arrow) == LightColors.green_arrow)
{
    //Turn
}

Статические элементы класса Class смогут поддерживать это многократное состояние без дополнительной функциональности.

Тем не менее, участники статического класса замечательны для широко используемых объектов. Участники System.drawing.Color являются отличными примерами, поскольку они представляют собой известные цвета, которые имеют неясные конструкторы (если вы не знаете своими шестигранниками). Если бы они были реализованы как enums, вам придется сделать что-то подобное каждый раз, когда вы хотите использовать значение в виде цвета:

colors c = colors.red;
switch (c)
{
    case colors.red:
        return System.Drawing.Color.FromArgb(255, 0, 0);
        break;
    case colors.green:
        return System.Drawing.Color.FromArgb(0,255,0);
        break;
}

, так что если у вас есть enum и обнаруживаю, что ваша постоянно выполняя переключатель / случай / если / В остальном / все, что нужно получить объект, вы можете использовать участники статического класса. Если вы только запрашиваете состояние чего-либо, я бы придерживаюсь съемами. Кроме того, если вам нужно пройти данные в небезопасных модах, вероятно, выживет лучше, чем сериализованная версия вашего объекта.

Редактировать: @stakx, я думаю, что ты наткнулся на что-то важное, тоже в ответ на почту @ Антон, и это сложность или более важно, кто это сложно для?

с точки зрения потребителя, я бы очень предпочитал систему. Члены классов над необходимостью написать все это. Однако от точки зрения продюсера, это была бы боль, чтобы написать все это. Поэтому, если другие люди будут использовать ваш код, вы можете сэкономить их большим количеством проблем, используя статические члены класса, даже если он может занять в 10 раз долго, чтобы написать / тестировать / отладки. Однако, если вам только вы, возможно, упростите просто использовать Enums и Chast / Converty по мере необходимости.

27
ответ дан 27 November 2019 в 19:28
поделиться

Я на самом деле боролся с чем-то вроде этого довольно немного на работе.

Он был основан на примере , который был опубликован Джоном Б в Статьей блога Джони Скеете «Усиленные перечисления в C #» .

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

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

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

Другая проблема была сериализация XML, которую мы много используем. Я побрался на то, что используя два общих класса в виде данных на передачи данных на переменные перечисления на наших бизнес-объектах: тот, который представлял одно значение перечисления, и тот, который представлял собой набор значений перечисления, которые я использовал для поведения подчеркивания флагов. Они обрабатывали сериализацию XML и десериализацию фактических значений, которые были сохранены в свойствах, которые они представляли. Пара операторных перегрузок были все, что необходимо было воссоздать поведение Bitflag таким образом.

Это некоторые из главных средств, в которых я столкнулся.

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

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

У вас нет ни одного кода, и я не смогу добраться до него на выходные, иначе я мог бы показаться, где я пошел с ним. Не очень красиво, хотя ...: O

3
ответ дан 27 November 2019 в 19:28
поделиться

Оба подхода действительны. Вы должны выбрать на случай.

Я могу добавить, что enums поддерживает поддержание битных операций в качестве флагов (есть даже атрибут [флаги] для поддержки этой семантики и создавать красивые строки от Enums).

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

1
ответ дан 27 November 2019 в 19:28
поделиться

YUP, оригинальное издание «Эффективного Java» от Joshua Bloch, которое было выпущено до Java 1.5 и нативную поддержку Enums в Java, продемонстрировало Veryfafe Enum . К сожалению, последний выпуск книги Targets Java> 1.5, поэтому вместо этого он использует java enums.

Во-вторых, вы не можете бросить от int enum в Java.

Color nonsenseColor = (Color)17; // compile-error

Я не могу говорить на других языках, хотя.

0
ответ дан 27 November 2019 в 19:28
поделиться

Некоторые вещи, которые я нашел в то же время, если кто-то заинтересован:

  • коммутатор блоки не будут работать с помощью enum-kss класса.

  • Пользователь Empi упомянул сходство приведенного выше образец inum-класса в java enums. Кажется, что в мире Java есть признанный шаблон, называемый The Sharefafe Spiritfafe ; Видимо, этот образец возвращается к книге Джошуа Блоха Эффективной Java .

2
ответ дан 27 November 2019 в 19:28
поделиться

Я бы использовал константы класса, когда мне приходится взаимодействовать с некоторым наследием кода, который хочет, чтобы некоторые неясные значения флага битового флага, которые могут быть или вместе. В этом случае Enum может выглядеть

public enum Legacy : ushort
{
  SomeFlag1 = 0x0001,
  SomeFlag2 = 0x0002,
  // etc...
}

, то маршаллинг на P / Invoke менее читается из-за литья, необходимого для перевода Enum в соответствующее значение.

Если бы это был переменная класса CONSS, актерский актерски не нужен.

1
ответ дан 27 November 2019 в 19:28
поделиться
Другие вопросы по тегам:

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