Если я использую оператор switch для обработки значений из перечисления (принадлежащего моему классу) и у меня есть регистр для каждого возможного значения - стоит ли добавлять код для обработки случая «по умолчанию»?
enum MyEnum
{
MyFoo,
MyBar,
MyBat
}
MyEnum myEnum = GetMyEnum();
switch (myEnum)
{
case MyFoo:
DoFoo();
break;
case MyBar:
DoBar();
break;
case MyBat:
DoBat();
break;
default:
Log("Unexpected value");
throw new ArgumentException()
}
Я не думаю, что это потому, что этот код никогда не может быть достигнут (даже с юнит-тестами). Мой коллега не согласен и считает, что это защищает нас от неожиданного поведения, вызванного добавлением новых значений в MyEnum.
Что скажете вы, сообщество?
MyEnum
затем передает его через ваш переключатель?switch
оператор.Ответы:
Включение регистра по умолчанию не меняет способ работы вашего кода, но делает его более понятным. Делая код очевидным образом (регистрируйте сообщение и создавайте исключение), вы добавляете большую красную стрелку для стажера, которого ваша компания наймет следующим летом, чтобы добавить пару функций. Стрелка говорит: «Эй, ты! Да, я разговариваю с тобой! Если ты собираешься добавить еще одно значение в перечисление, тебе лучше добавить и здесь дело». Это дополнительное усилие может добавить несколько байтов к скомпилированной программе, что необходимо учитывать. Но это также спасет кого-то (может быть, даже вас в будущем) где-то между часом и днем непродуктивной царапины на голове.
Обновление: описанная выше ситуация, то есть защита от значений, добавленных в перечисление в более позднее время, также может быть обнаружена компилятором. Clang (и gcc, я думаю) по умолчанию выдаст предупреждение, если вы включите перечислимый тип, но у вас нет регистра, который бы охватывал все возможные значения в перечислении. Так, например, если вы удалите
default
регистр из переключателя и добавите новое значениеMyBaz
в перечисление, вы получите предупреждение:Разрешение компилятору обнаруживать нераскрытые случаи заключается в том, что он в значительной степени устраняет необходимость в этом недоступном
default
случае, который вдохновил ваш вопрос в первую очередь.источник
Я только что говорил с коллегой об этом и сегодня утром - это очень прискорбно, но я думаю, что обработка по умолчанию необходима для безопасности по двум причинам:
Во-первых, как упоминает ваш коллега, он защищает код от новых значений, добавляемых в enum. Это может или не может показаться возможным, но это всегда есть.
Что еще более важно, в зависимости от языка / компилятора, может быть возможным иметь значения, которые не являются членами перечисления в вашей переключаемой переменной. Например, в C #:
Добавляя простое
case default:
и выбрасывая исключение, вы защищаете себя от этого странного случая, когда «ничего» не происходит, но «что-то» должно было случиться.К сожалению, практически каждый раз, когда я пишу оператор switch, это потому, что я проверяю случаи перечисления. Мне бы очень хотелось, чтобы поведение «выбросить по умолчанию» могло быть реализовано самим языком (хотя бы путем добавления ключевого слова).
источник
Добавление случая по умолчанию, даже если вы никогда не ожидаете его достижения, может быть полезным. Это значительно упростит отладку, если ваш код генерирует исключение «Этого не должно было случиться» сразу же, а не позже, в программе, вызывая какое-то загадочное исключение или возвращая неожиданные результаты без ошибок.
источник
Я говорю:
Попробуйте добавить другой тип
MyEnum
. Затем измените эту строку:в
Затем запустите ваш код с регистром по умолчанию и без регистра по умолчанию. Какое поведение вы предпочитаете?
Наличие регистра по умолчанию также может быть полезно для захвата
NULL
значений и предотвращенияNullPointerExceptions
.источник
Если бы вы знали, как можно сэкономить время, настаивая на случае по умолчанию, вам не нужно задавать вопрос. Молчаливая бездействие в состоянии ошибки недопустимо - вы молча ловите исключения, которые никогда не должны происходить? Оставлять «мины» для программистов, которые следуют за вами, также недопустимо.
Если ваш код никогда не будет изменен или изменен и на 100% свободен от ошибок, исключая регистр по умолчанию, возможно, все в порядке.
Ада (прародитель надежных языков программирования) не скомпилирует переключатель перечисления, если только все перечисления не охвачены или нет обработчика по умолчанию - эта функция есть в моем списке пожеланий для каждого языка. Наш стандарт кодирования Ada гласит, что при включении перечислений явная обработка всех значений без значения по умолчанию является предпочтительным способом решения этой ситуации.
источник