Для представления набора связанных констант с символьными именами язык C# предоставляет инструмент: типы перечислений – enum‘ы. О том как создавать и работать с объектами такого типа будет рассказано в данном уроке.
- Типы перечислений enum
- Работа с переменными типа перечисления
- Тип System.Enum
- Определение типа элемента перечисления
- Конвертация числа в константу перечисления
- Проверка наличия целочисленного (или строкового) значения в заданном перечислении
- Форматированное строковое представление значения перечисления
- Преобразование строки или числа в значение перечисления
- Получение имен элементов перечисления и их численных значений в виде массивов
- Битовые флаги
Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.
Типы перечислений enum
Тип перечисление (enum) представляет собой набор символьных имен, связанных с уникальными целочисленными значениями. Для объявления этого типа используется оператор enum. После оператора enum указывается имя создаваемого типа. Через двоеточие можно указать тип констант перечисления (должен быть целочисленным). Если не указывать тип явно, то будет использован int. После этого приводится список символьных констант через запятую. Пример типа перечисления:
enum TypeOS { Windows, Linux, MacOS, Android }
Каждому элементу перечисления присваивается целочисленное значение, в примере выше, эти значения начинаются с нуля и, далее, увеличиваются на единицу. Можно явно задать значения элементам перечисления. Для этого C# предоставляет два варианта: первый – это задание численного значения первому элементу, при этом все остальные, по очереди, принимают значения на единицу больше:
enum TypeOS { Windows = 1, Linux, MacOS, Android }
Второй вариант предполагает явное задание численных значений каждому элементу перечисления индивидуально:
enum TypeOS { Windows = 1, Linux = 3, MacOS = 5, Android = 7 }
Работа с переменными типа перечисления
Создадим следующий тип перечисление для экспериментов:
enum WeekDay { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }
С элементами типа перечисления можно производить различные операции – это приведение значения к целочисленному типу, операции сравнения (==, !=, <, > и т.п.), арифметические операции: сложение и вычитание, логические операции (&, |, ^), операция побитового дополнения (~) и операции постфиксного и префиксного инкремента (++) и декремента (–), более подробно про эти операции написано в “Уроке 4. Простые типы. Арифметические и логические операции“.
Выполним несколько операций с типом WeekDay:
WeekDay wd; int dayNum; wd = WeekDay.Friday; Console.WriteLine($"Пример дня недели: {wd}"); dayNum = (int)wd; Console.WriteLine($"{wd} идет в перечислении под номером {dayNum}"); wd -= 3; dayNum = (int)wd; Console.WriteLine($"{wd} идет в перечислении под номером {dayNum}");
Как было сказано в Уроке 6, enum может быть результатом выражения в операторе switch. Создадим метод, который в зависимости от дня недели будет выдавать занятие по расписанию:
static void WorkAtDay(WeekDay wd) { switch (wd) { case WeekDay.Monday: Console.WriteLine($"{wd} - Физкультура"); break; case WeekDay.Friday: Console.WriteLine($"{wd} - Литература"); break; case WeekDay.Wednesday: Console.WriteLine($"{wd} - Математика"); break; default: Console.WriteLine($"{wd} - День отдыха"); break; } }
Продемонстрируем работу этого метода:
WorkAtDay(WeekDay.Monday); WorkAtDay(WeekDay.Friday); WorkAtDay((WeekDay)3); WorkAtDay(WeekDay.Sunday);
Тип System.Enum
Базовым классом для всех перечислений является System.Enum. Он включает в себя различные методы, которые позволяют получить сведения о типе перечисления и его значениях. Далее будут более подробно рассмотрены возможности, предоставляемые этим классом. Создадим enum для представления времен года, с ним мы будем работать в разделах, приведенных ниже:
enum Season { Spring, Summer, Autumn, Winter }
Определение типа элемента перечисления
Для получения значения типа элемента перечисления используйте метод GetType непосредственно у самого элементы. Метод GetUnderlyingType у типа System.Enum возвращает базовый тип перечисления:
Console.WriteLine($"Тип элемента Season.Spring: {Season.Spring.GetType()}"); Console.WriteLine($"Базовый тип элемента Season.Spring: {Enum.GetUnderlyingType(Season.Spring.GetType())}");
Конвертация числа в константу перечисления
Метод ToObject конвертирует целочисленное значение в экземпляр перечисления указанного типа:
Type enumType = Season.Spring.GetType(); int n1 = 3; int n2 = 0; Console.WriteLine($"Преобразование числа {n1} в перечисление Season: {Enum.ToObject(enumType, n1)}"); Console.WriteLine($"Преобразование числа {n2} в перечисление Season: {Enum.ToObject(enumType, n2)}");
Необходимо учитывать, что если ToObject применить к числу, которое не совпадает со значениями у элементов перечисления, то метод будет выполнен, но ничего не преобразует:
int n3 = 5; Console.WriteLine($"Преобразование числа {n3} в перечисление Season {Enum.ToObject(enumType, n3)}");
Для исключения таких случаев рекомендуется перед преобразованием использовать метод IsDefined.
Проверка наличия целочисленного (или строкового) значения в заданном перечислении
Для проверки наличия заданного целочисленного значения или имени в виде строки среди элементов перечисления используется метод IsDefined(Type, Object), который в качестве аргументов принимает тип и значение для проверки:
int n4 = 5; Console.WriteLine($"Существует ли элемент под номером {n4} в перечислении: {Enum.IsDefined(enumType, n4)}");
Форматированное строковое представление значения перечисления
Метод Format предоставляет возможность форматированного конвертирования перечисления в строку:
var season = Season.Winter; Console.WriteLine($"Численное значение времени года {season}: {Enum.Format(typeof(Season), season, "d")}."); Console.WriteLine($"Значение в формате hex времени года {season}: {Enum.Format(typeof(Season), season, "x")}.");
Преобразование строки или числа в значение перечисления
Метод Parse преобразует строку (или число) в значение перечисления указанного типа. Значение и тип передаются в качестве аргументов методу, также можно дополнительно использоваться параметр ignoreCase для игнорирования регистра:
string[] arr = { "5", "0", "3", "Autumn", "Summer, Winter" }; foreach (var strVal in arr) { var seasonVal = (Season)Enum.Parse(typeof(Season), strVal, true); Console.WriteLine($"Преобразовали \"{strVal}\" в {seasonVal}"); }
Получение имен элементов перечисления и их численных значений в виде массивов
Для получения имен элементов перечисления в виде массива строк, используется метод GetNames:
Console.WriteLine("Элементы перечисления Season:"); foreach (string s in Enum.GetNames(typeof(Season))) { Console.WriteLine(s); }
Массив численных значений можно получить с помощью метода GetValues:
Console.WriteLine("Численные значения элементов перечисления Season:"); foreach (int s in Enum.GetValues(typeof(Season))) { Console.WriteLine(s); }
Битовые флаги
Перечисление можно представить как хранилище битовых флагов, это позволяет применять к элементам перечисления побитовые операции И (AND), ИЛИ (OR) и исключающее ИЛИ (XOR).
Для использования перечислений как наборов битовых флагов необходимо:
- При объявлении перечисления использовать атрибут flags.
- Константы должны быть определены как степень двойки. Для констант лучше использовать только положительные значения.
Ниже представлен пример, демонстрирующий работу с битовыми флагами:
[Flags] enum Mounts { January = 2, February = 4, March = 8, April = 16, May = 32, June = 64, July = 128, August = 256, September = 512, October = 1024, November = 2048, December = 4096, Winter = November | December | January } // Этот код нужно вставить в Main Mounts summerMount = Mounts.June | Mounts.July | Mounts.August; Console.WriteLine($"Летние месяцы: {summerMount}"); Mounts secondSemester = summerMount | Mounts.September | Mounts.October | Mounts.November; Console.WriteLine($"Осенние месяцы: { summerMount ^ secondSemester}");
Исходный код примеров из этой статьи можете скачать из нашего github-репозитория.
В последнем примере наименование перечисления с именем Mounts не очевидно. Наверное должно быть Months