Преимущества использования перечислений над непосредственным использованием интегральных типов?

1) я знаю о следующих преимуществах:

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

  • вы можете использовать их вместо магических чисел и тем самым сделать код более понятным

  • они также ограничивают значения enum переменная может иметь и при этом сделать приложение более безопасным, так как программисты знают, какие значения действительно для переменной, поэтому я думаю, что они обеспечивают безопасность типа

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

2) Почему они используют интегралы в качестве базового типа, а не строки?

спасибо

5 ответов


вы перечислили множество основных причин, по которым перечисления предпочтительнее интегральных типов.

  • именованные константы безопаснее и читабельнее, чем магические числа

  • перечисления описывают программистам, для чего они предназначены. Интегральные значения нет.

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

вы также можно добавить:

  • значительно увеличенный тип безопасность. Если вы принимаете "int", то любой int может быть передан. Если вы принимаете VehicleType, то только VehicalType можно пройти. Я не просто говорю о том, что кто-то проходит в 6, когда наибольшее допустимое число-5. Я имею в виду, что если вы пройдете в FuelType.Unleaded к функции, которая думает, что это означает VehicleType.Самолет? С перечислениями компилятор скажет вам, что вы идиот. Интегральный тип говорит: "Да, 5 меня устраивает" и ваша программа демонстрирует действительно странное поведение, которое может быть очень трудно отследить.

  • проще рефакторинг. Как и в случае с любыми магическими константами, если вы передадите значение 5 в сотне мест в своей программе, у вас будут проблемы, если вы решите изменить значение 5, чтобы иметь другое значение. С перечислением (если у вас нет проблем с двоичной обратной совместимостью) вы можете изменить базовые значения. Вы также можете изменить базовый тип перечисления, если хотите (байт - >int - > long), не делая ничего, кроме перекомпиляции кода клиента.

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

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

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

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

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

2) Зачем использовать байты или ints вместо строк? Просто они маленькие и эффективные.


Я бы предположил, что они требуют базовых интегральных типов для обеспечения простоты сравнения и более легкой поддержки битовых флагов. Без этого ограничения нам, компилятору или среде выполнения, вероятно, придется прибегнуть к некоторой нечеткости, чтобы делать такие вещи, как комбинации, или мы попадем в ситуацию, когда - как вы говорите - мы не стоит заботьтесь о базовом типе (точке абстракции), и все же, когда мы пытаемся сказать A | B мы получим ошибку времени выполнения, потому что мы используется базовый тип, который не способен выполнять операции такого типа.


одно преимущество, когда вы хотите использовать перечисление в качестве флага.

поэтому, если вы определяете перечисление, как это:

[Flags]
public enum TestEnum{ A, B, C, D };

тогда, если у вас есть метод, который принимает экземпляр TestEnum в качестве переменной, вы можете объединить значения из перечисления, чтобы вы могли отправить, например A | B | C в качестве параметра для метода. Затем, внутри метода, вы можете проверить параметр следующим образом:

if ((paramname & TestEnum.A) > 0) 
{
  //do things related to A
}
if ((paramname & TestEnum.B) > 0) 
{
  //do things related to B
}
//same for C and D

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

также относительно комментария, что вы можете ввести неправильное значение в перечисление с таким кодом (TestEnum)500; это трудно сделать, если вы не хотите сломать ваш код.

точка, в которой значение 0 для перечисления должно быть значением по умолчанию, или в случае флагов "отсутствие всех других флагов" очень важна, так как строка TestEnum myenum будет instanciate myenum как 0 независимо от того, определены значения enum для 0 или нет.


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

Я думаю, вы продали меня на перечисления в "magic numbers".


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

Другим преимуществом является то, что перечисленные константы генерируются компилятором автоматически.
Например, если у вас есть перечисляемый тип константы для кодов ошибок, которые могут возникнуть в вашей программе, ваше определение перечисления может выглядеть примерно так: перечисление Код_ошибки { НЕХВАТКА ПАМЯТИ, FILE_NOT_FOUND }; Out_of_memory автоматически присваивается значение 0 (ноль) компилятором потому что он появляется первым в определении.FILE_NOT_FOUND равно 1, и так далее. Если вы подходите к тому же примеру, используя символьные константы или магические числа, вы пишете гораздо больше кода, чтобы сделать то же самое.