Перечисления enum C#

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

Про перечисления (enum) в C# мы пока только знаем, что они есть и, согласно принятой классификации типов данных C# enum относится к типам значений или значимым типам (тут кому как удобнее называть). Сегодня мы попробуем разобраться с тем, как определяются и используются перечисления enum в C#, какие операции можно выполнять с перечислениями и напишем небольшой пример, демонстрирующий использование перечислений в C#.

Как определить enum в проекте C#

Перечисление (enum) — это пользовательский тип данных, представляющий собой набор именованных целочисленных констант. Чтобы объявить перечисление enum в своем приложении необходимо использовать ключевое слово enum и придерживаться следующего правила:

enum Название_типа : целочисленный_тип
{
    имена_констант_через_запятую
}

Вначале идет ключевое слово enum, которое указывает на то, что тип данных относится к перечислениям. Далее идет Название_типа — это может быть любая строка допустимая для использования в именах переменных C#. После названия через двоеточие указывается тип данных для констант в перечислении, если тип не указан, то по умолчанию используется тип int. И, наконец, в фигурных скобках через запятую указываются имена констант для перечисления. Например, ниже представлено перечисление, содержащее дни недели:

enum Days
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

Значения констант в enum

В самом начале было сказано, что enum — это, по сути, набор именованных целочисленных констант. По умолчанию связанные значения констант элементов перечисления имеют тип int. Они начинаются с нуля и увеличиваются на единицу в соответствии с порядком текста определения. Чтобы убедиться в этом, достаточно написать, например, вот такой код:

namespace EnumApp
{
    enum Days
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"{nameof(Days.Monday)} = {(int)Days.Monday}");
            Console.WriteLine($"{nameof(Days.Tuesday)} = {(int)Days.Tuesday}");
            Console.WriteLine($"{nameof(Days.Wednesday)} = {(int)Days.Wednesday}");
            Console.WriteLine($"{nameof(Days.Thursday)} = {(int)Days.Thursday}");
            Console.WriteLine($"{nameof(Days.Friday)} = {(int)Days.Friday}");
            Console.WriteLine($"{nameof(Days.Saturday)} = {(int)Days.Saturday}");
            Console.WriteLine($"{nameof(Days.Sunday)} = {(int)Days.Sunday}");
        }
    }
}
nameof(...) — это выражение, с помощью которого можно получить имя переменной в виде строки.

и увидеть в консоли следующее:

Monday = 0
Tuesday = 1
Wednesday = 2
Thursday = 3
Friday = 4
Saturday = 5
Sunday = 6

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

 enum Days {
    Monday = 5,
    Tuesday = 7,
    Wednesday = 10,
    Thursday = 18,
    Friday = 25,
    Saturday = 48,
    Sunday = 64
}

Можем указать свой собственный тип данных для констант:

enum Days : short
{
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 5,
    Friday = 5,
    Saturday = -1,
    Sunday = -2
}

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

enum Days : byte
{
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 5,
    Friday = 5,
    Saturday = 10,
    Sunday = -1
}

то компилятор C# выдаст нам ошибку:

Ошибка CS0031 Значение константы «-1» не может быть преобразовано в «byte».

потому что тип byte может иметь значения от 0 до 255. При этом, в перечислениях константы могут иметь одинаковые значения или использоваться для определения других констант:

enum Days : byte
{
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 5,
    Friday = 5,
    Saturday = 1,
    Sunday = Saturday + 2
}

Пример использования перечислений

Рассмотрим следующий пример использования перечислений в C#

namespace EnumApp
{
    enum Operation
    {
        Add,
        Subtract,
        Multiply,
        Divide
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Введите первое целое число:");
            int num1 = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("Введите второе целое число:");
            int num2 = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("0 - сложение");
            Console.WriteLine("1 - вычитание");
            Console.WriteLine("2 - умножение");
            Console.WriteLine("3 - деление");
            Operation operNum = (Operation)Convert.ToInt32(Console.ReadLine());
            switch (operNum) 
            {
                case Operation.Add: 
                    {
                        Console.WriteLine($"{num1} + {num2} = {num1 + num2}");
                        break; 
                    }
                case Operation.Subtract: 
                    {
                        Console.WriteLine($"{num1} - {num2} = {num1 - num2}");
                        break; 
                    }
                case Operation.Multiply: 
                    {
                        Console.WriteLine($"{num1} * {num2} = {num1 * num2}");
                        break; 
                    }
                case Operation.Divide: 
                    {
                        Console.WriteLine($"{num1} / {num2} = {(double)num1 / num2}");
                        break; 
                    }
            }
        }
    }
}

Вначале мы просим ввести пользователя два целых числа:

Console.WriteLine("Введите первое целое число:");
int num1 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Введите второе целое число:");
int num2 = Convert.ToInt32(Console.ReadLine());

Метод Convert.ToInt32() позволяет нам преобразовать строку в число. Про класс Convert и его методы преобразования есть отдельная заметка. Далее, пользователь выбирает одну из четырех операций — сложение, вычитание, умножение, деление и вводит число от 0 до 3, соответствующее выбранной операции. Тип перечисления описан выше — Operation. И здесь стоит обратить внимание на следующую строку:

Operation operNum = (Operation)Convert.ToInt32(Console.ReadLine());

здесь мы, во-первых, получаем из строки число — Convert.ToInt32(Console.ReadLine()), а, во-вторых присваиваем переменной operNum значение из перечисления Operation, соответствующее этому числу: Operation operNum = (Operation)[результат]. Чтобы было понятнее, то же самое действие мы могли бы расписать в коде более подробно, используя промежуточную переменную:

int op = Convert.ToInt32(Console.ReadLine());//получили число от 0 до 3
Operation operNum = (Operation)op; //получили значение из Operation

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

switch (operNum) 
{
    case Operation.Add: 
        {
            Console.WriteLine($"{num1} + {num2} = {num1 + num2}");
            break; 
        }
    case Operation.Subtract: 
        {
            Console.WriteLine($"{num1} - {num2} = {num1 - num2}");
            break; 
        }
    case Operation.Multiply: 
        {
            Console.WriteLine($"{num1} * {num2} = {num1 * num2}");
            break; 
        }
    case Operation.Divide: 
        {
            Console.WriteLine($"{num1} / {num2} = {(double)num1 / num2}");
            break; 
        }
}

В итоге, можно получить вот такой результат работы приложения:

Введите первое целое число:
1
Введите второе целое число:
2
0 — сложение
1 — вычитание
2 — умножение
3 — деление
3
1 / 2 = 0,5

Этот пример, конечно, простой и не раскрывает до конца всей важности использования перечислений в C#. По-настоящему, вся красота использования перечислений раскрывается во втором случае — когда константы используются в качестве битовых флагов.

Перечисления C# как битовые флаги

В теме про побитовые операторы и операторы сдвига мы уже затрагивали вопрос об использовании битовых флагов в C#. В языке C# мы можем использовать перечисления enum в качестве битовых флагов. Для демонстрации примера воспользуемся следующим перечислением:

enum Days { 
    Monday, 
    Tuesday, 
    Wednesday, 
    Thursday, 
    Friday,
    Saturday, 
    Sunday
}

Для того, чтобы каждая константа перечисления стала битовым флагом:

  • её значение должно быть степенью двойки
  • к перечислению необходимо применить атрибут [Flags]

Что касается второго пункта — применения атрибутов, то с таким понятием, как атрибуты мы будем довольно часто встречаться, а некоторые из них даже рассматривать подробно. Пока же можно сказать так: атрибут в C# — это специальная конструкция языка (аннотация кода) с помощью которой мы можем указывать компилятору, какой-то части .NET или даже другому программисту, что необходимо сделать с элементом. В нашем случае, мы с помощью атрибута [Flags] указываем компилятору, что будем работать с перечислением как с битовыми флагами. В итоге, наше перечисление Days примет следующий вид:

[Flags]
enum Days { 
    Monday = 1, 
    Tuesday = 2, 
    Wednesday = 4, 
    Thursday = 8, 
    Friday = 16,
    Saturday = 32, 
    Sunday = 64
}

Более того, мы можем создать новый флаг, например, так:

[Flags]
enum Days { 
    Monday = 1, 
    Tuesday = 2, 
    Wednesday = 4, 
    Thursday = 8, 
    Friday = 16,
    Saturday = 32, 
    Sunday = 64,
    Weekend = Saturday | Sunday //применяем логическое сложение
}

последний элемент перечисления получен путем логического сложения дней, относящихся к выходным (субботы и воскресенья). Соответственно, раз мы используем битовые флаги, то для проверки наличия определенного флага в битовой маске мы должны использовать логическое И (логическое умножение). Например,

internal class Program
{
    static void Main(string[] args)
    {
        var monday = Days.Monday;
        var saturday = Days.Saturday;
        //проверка битового флага среди выходных дней
        if ((monday & Days.Weekend) == 0) //проверка отсутствия флага в маске
        {
            Console.WriteLine("Понедельник - это рабочий день");
        }

        if ((saturday & Days.Saturday) != 0) //проверка присутствия флага в маске
        {
            Console.WriteLine("Суббота - это выходной день");
        }
    }
}

Второй вариант проверки флага в битовой маске — использование метода enum.HasFlag() для этого перепишем наш метод Main() следующим образом:

internal class Program
{
    static void Main(string[] args)
    {
        var monday = Days.Monday;
        var saturday = Days.Saturday;
        //проверка битового флага среди выходных дней

        if (Days.Weekend.HasFlag(monday) == false)
        {
            Console.WriteLine("Понедельник - это рабочий день");
        }

        if (Days.Weekend.HasFlag(saturday) == true)
        {
            Console.WriteLine("Суббота - это выходной день");
        }
    }
}

Итого

Использование перечислений enum в C# может носить самый разнообразный характер, например, для хранение состояния какого-либо объекта в программе или, как в нашем случае, для указания типа операции над парой чисел. В любом случае, перечисления помогают нам сделать код программы более понятным. Согласитесь, что, вот такой вызов метода:

DoOperation(10, 3, Ariphm.Divide);

Намного понятнее, чем:

DoOperation(10, 3, -20);

а если учесть, что во втором случае пользователь может вызвать метод и вот так:

DoOperation(10, 3, -134);

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

уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
guest
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии