Поделиться через


Проектирование перечисления

Замечание

Это содержимое перепечатывается разрешением Pearson Education, Inc. из руководства по проектированию платформы: соглашения, идиомы и шаблоны для повторно используемых библиотек .NET, 2-го выпуска. Этот выпуск был опубликован в 2008 году, и книга с тех пор была полностью пересмотрена в третьем выпуске. Некоторые сведения на этой странице могут быть устаревшими.

Перечисления — это особый тип значения. Существует два типа перечислений: простые перечисления и флаговые перечисления.

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

Перечисления с флагами предназначены для поддержки побитовых операций со значениями перечислений. Типичным примером перечисления флагов является список параметров.

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

✔️ Стоит предпочитать использовать перечисление вместо статических констант.

❌ Не используйте перечисление для открытых наборов (например, версию операционной системы, имена друзей и т. д.).

❌ НЕ предоставляйте зарезервированные значения перечислений, которые предназначены для будущего использования.

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

❌ Избегайте публичного раскрытия перечислений с единственным значением.

Распространенная практика обеспечения дальнейшего расширения API C заключается в добавлении зарезервированных параметров для подписей методов. Такие зарезервированные параметры можно выразить как перечисления с одним значением по умолчанию. Это не должно быть сделано в управляемых API. Перегрузка метода позволяет добавлять параметры в будущие выпуски.

❌ НЕ включать специальные контрольные значения (sentinel values) в перечисления.

Хотя они иногда полезны для разработчиков платформы, сторожевые значения могут ввести в заблуждение пользователей платформы. Они используются, чтобы отслеживать состояние перечисления, а не для того чтобы быть одним из значений из набора, представленного перечислением.

✔️ Установите значение нуля для простых перечислений.

Рассмотрите возможность назвать значение, например "Нет". Если такое значение не подходит для конкретного перечисления, наиболее распространённому значению по умолчанию для перечисления должно быть назначено значение равное нулю.

✔️ Рассмотрите возможность использования Int32 (по умолчанию в большинстве языков программирования) в качестве базового типа перечисления, если не выполняется ни одно из следующих условий:

  • Перечисление представляет собой перечисление флагов, и у вас более 32 флагов или ожидается, что в будущем будет больше.

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

  • Меньший базовый тип приведет к значительной экономии пространства. Если вы ожидаете, что перечисление будет использоваться главным образом как аргумент для управления потоком, размер не имеет большого значения. Экономия размера может быть значительной, если:

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

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

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

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

✔️ Именуйте перечисления-флаги существительными во множественном числе или фразами существительных, а простые перечисления — существительными в единственном числе или фразами существительных.

❌ Не расширяйте System.Enum напрямую.

System.Enum — это специальный тип, используемый средой CLR для создания определяемых пользователем перечислений. Большинство языков программирования предоставляют элемент программирования, который предоставляет доступ к этой функции. Например, в C# ключевое enum слово используется для определения перечисления.

Проектирование перечисления флагов

Применяйте System.FlagsAttribute к флаговым перечислениям. Не применяйте этот атрибут к простым перечислениям.

✔️ Используйте степени двойки для значений перечисления флага, чтобы их можно было свободно объединять с помощью побитовой операции ИЛИ.

✔️ Рассмотрите возможность предоставления специальных значений перечисления для часто используемых сочетаний флагов.

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

❌ Избегайте создания перечислений флагов, в которых определенные сочетания значений недопустимы.

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

✔️ Указывайте нулевое значение флаговых перечислений None. Для перечисления флагов значение всегда должно означать "все флаги очищены".

Добавление ценности в перечисления

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

Рассмотрите возможность добавления значений в перечисления, даже если это несет небольшой риск для совместимости.

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

© Часть 2005, 2009 Корпорация Майкрософт. Все права защищены.

Перепечатан с разрешения Pearson Education, Inc. из Руководство по проектированию: Соглашения, идиомы и шаблоны для повторного использования библиотек .NET, 2-е издание Кшиштоф Чвалина и Брэд Абрамс, опубликованное 22 октября 2008 года Addison-Wesley Профессиональный в рамках серии разработки Microsoft Windows.

См. также