19 Перечисления
19.1 Общие
Тип перечисления — это отдельный тип значения (§8.3), который объявляет набор именованных констант.
Пример: пример
enum Color { Red, Green, Blue }
объявляет тип перечисления с именами
Color
членовRed
иGreen
Blue
.пример конца
Объявления перечисления 19.2
Объявление перечисления объявляет новый тип перечисления. Объявление перечисления начинается с ключевого слова enum
и определяет имя, специальные возможности, базовый тип и члены перечисления.
enum_declaration
: attributes? enum_modifier* 'enum' identifier enum_base? enum_body ';'?
;
enum_base
: ':' integral_type
| ':' integral_type_name
;
integral_type_name
: type_name // Shall resolve to an integral type other than char
;
enum_body
: '{' enum_member_declarations? '}'
| '{' enum_member_declarations ',' '}'
;
Каждый тип перечисления имеет соответствующий целочисленный тип, называемый базовым типом перечисления. Этот базовый тип должен представлять все значения перечислителя, определенные в перечислении. Если enum_base присутствует, он явно объявляет базовый тип. Базовый тип должен быть одним из целочисленных типов (§8.3.6), отличных char
от . Базовый тип может быть указан либо в формате integral_type
(§8.3.5), либо в виде integral_type_name
. Разрешение integral_type_name
разрешается таким же образом, как type_name
и (§7.8.1), включая принятие любых директив using (§14.5) в учет.
Примечание. Тип
char
не может использоваться в качестве базового типа либо по ключевому слову, либо по ключевому словуintegral_type_name
. конечная заметка
Объявление перечисления, которое явно не объявляет базовый тип, имеет базовый тип int
.
Пример: пример
enum Color : long { Red, Green, Blue }
объявляет перечисление с базовым типом
long
.пример конца
Примечание. Разработчик может использовать базовый тип
long
, как в примере, чтобы включить использование значений, которые находятся в диапазоне, но не в диапазонеlong
int
или сохранить этот параметр в будущем. конечная заметка
Примечание. C# разрешает запятую в enum_body так же, как и в array_initializer (§17.7). конечная заметка
Объявление перечисления не может включать список параметров типа, но любые перечисления, вложенные в объявление универсального класса или универсальное объявление структуры, является универсальным объявлением перечисления, так как аргументы типа для содержащего типа должны быть предоставлены для создания созданного типа (§8.4).
19.3 Модификаторы перечисления
При необходимости enum_declaration может содержать последовательность модификаторов перечисления:
enum_modifier
: 'new'
| 'public'
| 'protected'
| 'internal'
| 'private'
;
Это ошибка во время компиляции для одного модификатора, который будет отображаться несколько раз в объявлении перечисления.
Модификаторы объявления перечисления имеют то же значение, что и объявление класса (§15.2.2). abstract
Однако модификаторы и static
sealed
модификаторы не допускаются в объявлении перечисления. Перечисления не могут быть абстрактными и не разрешают производные.
Элементы перечисления 19.4
Текст объявления типа перечисления определяет ноль или несколько элементов перечисления, которые являются именованными константами типа перечисления. Два элемента перечисления не могут иметь одинаковое имя.
enum_member_declarations
: enum_member_declaration (',' enum_member_declaration)*
;
enum_member_declaration
: attributes? identifier ('=' constant_expression)?
;
Каждый член перечисления имеет связанное константное значение. Тип этого значения является базовым типом для содержащего перечисления. Константное значение для каждого элемента перечисления должно находиться в диапазоне базового типа перечисления.
Пример: пример
enum Color: uint { Red = -1, Green = -2, Blue = -3 }
приводит к ошибке во время компиляции, так как константные значения
-1
-2
, и-3
не находятся в диапазоне базового целочисленного типаuint
.пример конца
Несколько членов перечисления могут совместно использовать одно и то же связанное значение.
Пример: пример
enum Color { Red, Green, Blue, Max = Blue }
отображает перечисление, в котором два члена перечисления —
Blue
и имеют одно иMax
то же связанное значение.пример конца
Связанное значение элемента перечисления назначается неявно или явно. Если объявление элемента перечисления имеет инициализатор constant_expression , значение этого константного выражения, неявно преобразованное в базовый тип перечисления, является связанным значением элемента перечисления. Если объявление элемента перечисления не имеет инициализатора, его связанное значение задается неявно, как показано ниже.
- Если элемент перечисления является первым элементом перечисления, объявленным в типе перечисления, его связанное значение равно нулю.
- В противном случае связанное значение элемента перечисления получается путем увеличения связанного значения текстового элемента перечисления по одному. Это увеличенное значение должно находиться в диапазоне значений, которые могут быть представлены базовым типом, в противном случае возникает ошибка во время компиляции.
Пример: пример
enum Color { Red, Green = 10, Blue } class Test { static void Main() { Console.WriteLine(StringFromColor(Color.Red)); Console.WriteLine(StringFromColor(Color.Green)); Console.WriteLine(StringFromColor(Color.Blue)); } static string StringFromColor(Color c) { switch (c) { case Color.Red: return $"Red = {(int) c}"; case Color.Green: return $"Green = {(int) c}"; case Color.Blue: return $"Blue = {(int) c}"; default: return "Invalid color"; } } }
выводит имена элементов перечисления и их связанные значения. Результат выглядит так:
Red = 0 Green = 10 Blue = 11
по следующим причинам:
- элемент
Red
перечисления автоматически присваивается нулю значения (так как он не имеет инициализатора и является первым элементом перечисления);- член
Green
перечисления явно присваивается значению10
;- и член
Blue
перечисления автоматически присваивается значению, большему, чем элемент, который текстуально предшествует ему.пример конца
Связанное значение элемента перечисления не должно, прямо или косвенно, использовать значение собственного связанного элемента перечисления. Кроме этого ограничения цикличности, инициализаторы элементов перечисления могут свободно ссылаться на другие инициализаторы элементов перечисления независимо от их текстовой позиции. В инициализаторе элемента перечисления значения других элементов перечисления всегда рассматриваются как тип базового типа, поэтому при обращении к другим элементам перечисления не требуется.
Пример: пример
enum Circular { A = B, B }
приводит к ошибке во время компиляции, так как объявления
A
иB
являются циклическими.A
B
зависит от явногоB
и зависит отA
неявно.пример конца
Элементы перечисления именуются и определяются точно аналогично полям в классах. Область элемента перечисления — это тело его содержащего типа перечисления. В этой области члены перечисления могут ссылаться на их простое имя. Из всего другого кода имя члена перечисления должно быть квалифицировано с именем его типа перечисления. Элементы перечисления не имеют объявленной специальных возможностей— элемент перечисления доступен, если он содержит тип перечисления доступен.
19.5 Тип System.Enum
Тип System.Enum
является абстрактным базовым классом всех типов перечисления (это отличается от базового типа перечисления), а элементы, унаследованные от System.Enum
них, доступны в любом типе перечисления. Преобразование бокса (§10.2.9) существует из любого типа System.Enum
перечисления в , а преобразование распаковки (§10.3.7) существует от System.Enum
любого типа перечисления.
Обратите внимание, что System.Enum
это не сам enum_type. Скорее, это class_type , из которого производны все enum_type. Тип System.Enum
наследуется от типа System.ValueType
(§8.3.2), который, в свою очередь, наследует от типа object
. Во время выполнения значение типа System.Enum
может быть null
или ссылка на поле любого типа перечисления.
19.6 Значения и операции перечисления
Каждый тип перечисления определяет отдельный тип; Явное преобразование перечисления (§10.3.3) требуется для преобразования между типом перечисления и целочисленным типом или между двумя типами перечисления. Набор значений типа перечисления совпадает с набором значений базового типа и не ограничивается значениями именованных констант. Любое значение базового типа перечисления может быть приведение к типу перечисления и является уникальным допустимым значением этого типа перечисления.
Элементы перечисления имеют тип своего типа перечисления (за исключением других инициализаторов элементов перечисления: см . статью 19.4). Значение элемента перечисления, объявленного в типе E
перечисления со связанным значением v
(E)v
.
Следующие операторы можно использовать для значений типов перечисления:
==
,!=
,<
>
>=
<=
(§12.12.6)- binary
+
(§12.10.5) - binary
-
(§12.10.6) ^
, (&
|
§12.13.3)~
(§12.9.5)++
,--
(§12.8.15 и §12.9.6)sizeof
(§23.6.9)
Каждый тип перечисления автоматически наследуется от класса System.Enum
(который, в свою очередь, является производным от System.ValueType
и object
). Таким образом, унаследованные методы и свойства этого класса можно использовать для значений типа перечисления.
ECMA C# draft specification