За свою непродолжительную карьеру C# разработчика я успел поверхностно погрузиться во многие аспекты этого, без преувеличения, прекрасного языка. Наиболее любопытной из них для меня является такая, с первого взгляда, простая вещь, как перечисления или же enum, о коей я попытаюсь рассказать в этой статье.
Что же такое enum и на кой он вообще нужен?
Представим что нам необходимо определить такое свойство класса как цвет. Как-же нам решить эту проблему?
Мы можем сделать это через строковую переменную:

В данном примере мы имеем некий класс, обладающий параметром Color и методом, который проверяет, равен ли переданный в него цвет хранящемуся в классе. Согласен, пример дурацкий, но достаточно демонстративный. Попытаемся вызвать этот метод:

В результате выполнения кода значение check будет равно true, а secondCheck будет равно false. Вроде бы задача решена, в прод. Но человек существо не идеальное, и может случиться такое, что в метод будет передано не Red, а red или rad. Вроде-бы человек может догадаться что было ему сказано, но машина прямолинейна и догадываться не будет. В результате некорректного ввода метод будет возвращать false, хотя мы ожидаем true:

Конечно первый вид опечатки можно исправить дополнительной операцией приведения к нижнему регистру обеих строк перед сравнением. Но этого не сделать при второй опечатке. Значит строки нам не особо подходят.
Иным решением может быть хранение значений в численной переменной, заранее определив какому числу какое состояние соответствует.

Вроде-бы проблема решена: теперь никто не опечатается при вводе кода цвета. Но здесь всплывает другая проблема: человек не машина, и работать со словами ему на порядок проще чем с числами. Постоянно помнить, что 0 — это красный, а 1 — это синий, никакой памяти не напасёшься. А если человек поменяет проект и под номером 0 будет белый, а под 1 черный? Ерунда какая-то!!!
И тут нам на помощь приходит генная инженерия, позволяющая нарушить базовые законы колдовства и естества. Мы можем скрестить числа и строки!!! После столь противоестественного действия мы и получим любимый мною enum.
Enum-ом в базовом понимании называют некий список возможных, заранее определенных, именованных значений. Нужен этот список для того, чтобы упростить работу разработчику в оперировании некими состояниями. Решим нашу задачу с применением enum.

Как можно увидеть внизу нашего класса мы определили тот самый enum и сказали, что он может принимать 2 значения: Red и Blue. Теперь повторим вызов из примера со строками:

Как можно заметить, всё понятно, ясно, чЁтКо. А теперь попытаемся опечататься:

Редактор кода говорит, что я дурачок и не умею правильно писать слова. А это значит, что я могу заметить ошибку ещё до сборки и гарантированно её замечу во время сборки. Спасибо, добрый блокнот.
В принципе на этом можно было бы и закончить статью, но тогда какой в ней смысл, если это повествование можно было сократить раза в четыре. Непорядок! Поэтому, после базового пояснения что такое enum и нафига он нужен будут настоящие сенсации, от которых ряд моих знакомых C# разработчиков были удивлены. Внимание, барабанная дробь…
Enum это число!1!1!1
Как было сказано выше enum — это, по сути, плод запретной любви строки и числа. От строки, как было показано, опять-же, выше enum получил отличную человекочитаемость. От числа enum получил устойчивость к неправильному вводу. Но, помимо этого, от числа enum получил и внутренности.
По сути enum это обыкновенное число с табличкой. В примере выше это было не явно потому, что в списке были только имена, но не было чисел. Это не совсем правильный, хотя и рабочий по причине автопроставления чисел, подход к определению enum-а. Более правильным будет следующий подход:

Из того, что enum — это число с бейджиком, следует несколько особенностей:
-
Возможность приведения числа к enum.
-
Особенное приведение одного enum-а к другому.
Разберем эти особенности:
Приведение числа к enum
В ходе решения некой задачи нам может понадобиться на время расширить допустимый диапазон значений enum, но вот незадача, мы не хотим чтобы дополнительные значения были видны извне написанного нами кода, или же мы не имеем доступа к редактированию enum по причине того, что он не наш и поставляется нам сторонней библиотекой. Как же быть, спросите вы. А всё легко и просто, следите за руками.

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

Приведение одного enum к другому
Представим, что нам необходимо привести один enum к другому, например при маппинге одной структуры к другой. Как-же поведет себя enum? Определим пару enum-ов и попробуем это сделать:

В представленном примере мы создали два enum-а, один из которых обладает всеми значениями второго, но со смещенной из-за дополнительного значения нумерацией. Теперь попробуем привести первый enum ко второму:

Но как-же так, вроде же мы должны были получить значение Red, но получили White? Всё дело в том, что enum, как было сказано выше, является лишь именованным числом и приведение происходит именно по числовому значению. В случае необходимости подобного приведения потребуется написать дополнительный хендлер или явно описать каст через implicit/explicit.

Бонусный контент
Подобный пример был создан на основе комментария с просторов Метанита. Предположим мы решим в край упороться и написать следующий enum:

А затем посмотреть как он будет себя вести:

Что же за магия происходит в этом примере?
Поскольку у значения White явно не указано число, ему автоматически предоставляется число предыдущего значения +1, а поскольку это значение первое и перед ним ничего нет ему будет проставлено значение 0. Далее мы явно указываем для Black значение 0, что дублирует уже предоставленное значение для White. А поскольку White определено до Black, то и при обращении по значению 0 мы получим именно White.
В случае же color2, из-за описанной выше логики автопроставления чисел, значению Red было проставлено число 2+1=3. А при получении значения по числу вернулось первое в списке с таким числом.
Такие вот дела, ребята. А на сегодня всё.
ссылка на оригинал статьи https://habr.com/ru/post/701606/
Добавить комментарий