Должны ли перечисления иметь неинициализированные значения. - PullRequest
8 голосов
/ 06 декабря 2008

У нас была дискуссия о том, должны ли перечисления иметь неинициализированные значения. Например. У нас есть

public enum TimeOfDayType
{
   Morning
   Afternoon
   Evening
}

или

public enum TimeOfDayType
{
   None
   Morning
   Afternoon
   Evening
}

Я думаю, что не должно быть ничего, но тогда вы должны по умолчанию установить какое-то допустимое значение при инициализации. Но другие считали, что должно быть какое-то указание на унифицированное состояние, если есть другое перечисление None или NotSet.

мысли

Ответы [ 6 ]

13 голосов
/ 06 декабря 2008

Говоря об обнуляемых типах - я думаю, что они могут быть использованы для решения проблемы форсирования / не форсирования инициализации перечисления. Скажем, у нас есть

enum Color { Red, Blue }

И скажем, у вас есть функция:

void Draw(Color c);

Эта функция говорит, что требует действительного Color. Однако мы могли бы также иметь эту функцию:

void Draw(Color? c);

Это говорит о том, что функция может обрабатывать, не передавая цвет (null будет передано, чтобы указать «пофиг»).

Ну, это одна альтернатива None членов.

7 голосов
/ 06 декабря 2008

Я всегда устанавливаю один из моих литералов enum на ноль. Этот литерал не всегда должен называться «None» или «NotSet». Это зависит от того, есть ли литерал, который действует очень хорошо по умолчанию.

Я установил единицу на ноль, потому что перечисления (за исключением нуля перечисления) всегда инициализируются CLR в памяти на ноль. И если вы не определите один из литералов, эта память содержит недопустимые значения. Также, когда вы используете перечисления в качестве флагов. Значение по умолчанию нельзя использовать для побитовых сравнений. Результат всегда будет нулевым.

Когда вы включаете FxCop, он проверяет, определили ли вы литерал по умолчанию. Кажется, это «хорошая практика», когда у них есть правило для этого.

4 голосов
/ 06 декабря 2008

В отсутствие члена по умолчанию, я думаю, что полезно иметь значение, представляющее литерал int 0.

Независимо от того, что заданное перечисление будет создано с буквальным значением 0. Наиболее простой случай здесь - это член структуры. Структура C # всегда будет иметь пустой конструктор по умолчанию, который инициализирует все поля до значения по умолчанию. В случае перечисления это будет буквальное значение 0. Вопрос в том, как с этим справиться.

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

enum Color { Unknown, Red, Blue }
enum Color2 { Red,Blue }
struct Example<T> {
  Color color;
}

static void SomeMethod() {
  var v1 = new Example<Color>();
  var v2 = new Example<Color2>();
}

В случае v1, если поле цвета проверено, оно будет явно помечено как неинициализированное поле. В v2 поле будет просто «Красным». Программист не может обнаружить между и явным значением «Red» или неявным значением по умолчанию «Red».

Другим случаем, когда это вызывает проблему, является выполнение оператора switch для значения enum. Давайте немного изменим определение Color2.

enum Color2 { Red = 1, Blue = 2 }
static void SomeOtherMethod(p1 as Example<Color2>) {
  switch ( p1.color ) {
   case Color.Red: {} 
   case Color.Blue: {}
   default: {throw new Exception("What happened?"); }
  }
}

Переключатель обрабатывает каждое явное значение в перечислении. Тем не менее, этот код не будет работать для конструктора по умолчанию в Example , и нет способа подавить этот конструктор.

Это приводит к чуть более важному правилу: иметь явное значение перечисления для литерального значения 0.

4 голосов
/ 06 декабря 2008

Обнуляемое перечисление было предложено в качестве решения в некоторых из предыдущих ответов. Но у недействительного перечисления есть недостаток, заключающийся в том, что он заставляет клиентов проверять нулевое значение каждый раз, когда они используют перечисление. Напротив, если у вас есть значение по умолчанию «None», у вас есть возможность использовать переключатель для значимых значений и просто игнорировать «None», не беспокоясь о том, что переменная enum может быть нулевой.

В любом случае, я думаю, что иметь значение по умолчанию «None» или сделать перечисление обнуляемым имеет смысл, только если перечисление используется в качестве аргумента в конструкторе по умолчанию для некоторого класса. И вы должны спросить себя - не должны ли объекты этого класса иметь какое-либо значимое значение по умолчанию? Используя ваш пример с перечислением TimeOfDayType - если вы инициализируете объект с помощью TimeOfDayType.None, вы все равно не сможете использовать его, пока не измените значение на Утро, Полдень или Вечер. Так не могли бы вы сказать, что по умолчанию Утро вместо Нет? Или - что еще лучше - не могли бы вы создать свои объекты после того, как вы уже знаете, какое значение перечисления им нужно? Я думаю, что если проблема решается правильно на ранних стадиях проектирования, вам вообще не нужно специальное значение по умолчанию для ваших перечислений.

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

3 голосов
/ 06 декабря 2008

Просто добавив к ответу Фрэнка, один из тех случаев, когда я выбираю элемент «Нет» в перечислении вместо нуля, - это когда перечисление используется в качестве флагов. Элемент None будет иметь идентификатор 0.

1 голос
/ 06 декабря 2008

Зависит от того, как используется тип. Пользователям типа часто проще не иметь «неопределенное» значение, потому что вам не нужно указывать одно специальное значение. Но если вам нужно одно (поскольку значения иногда должны находиться в состоянии, которое в противном случае не является ни одним из перечисленных значений), тогда вам нужно одно. Обычно вы не сохраняете какой-либо специальный код, используя два перечисления вместо одного.

Это немного похоже на вопрос, должны ли вы использовать обнуляемые типы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...