оператор переключення - обробка випадку за замовчуванням, коли його неможливо досягти


16

Якщо я використовую оператор перемикання для обробки значень із enum (який належить моєму класу), і у мене є справа за кожним можливим значенням - чи варто додати код для обробки випадку "за замовчуванням"?

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 - це нерегульований тип.
sd

3
"Сьогодні" - це незмінне. А як завтра, коли ви більше не підтримуєте код. А як бути, коли "MyBiz" додається до переліку, але це не так? Зауваження Калеба щодо технічного обслуговування дуже германські.

1
Навчіть компілятора, що це фатальна помилка, якщо є перемикач, який охоплює не всі випадки.

Що робити, якщо хтось кидає недійсне значення, MyEnumа потім передає його через ваш комутатор?
Мауг каже, що повернути Моніку

1
Яка мова? Якщо Java, вам слід ввести метод всередині Enum і просто назвати його (поліморфізм), switchповністю усуваючи твердження.
user949300

Відповіді:


35

Включення випадку за замовчуванням не змінює спосіб роботи вашого коду, але робить ваш код більш рентабельним. Зробивши очевидний розрив коду (зареєструйте повідомлення та киньте виняток), ви включаєте велику червону стрілку для стажера, який ваша компанія наймає наступного літа, щоб додати пару функцій. Стрілка говорить: "Гей, ти! Так, я говорю з ВАС! Якщо ти збираєшся додати ще одне значення до перерахунків, то краще тут також додати справу". Ці додаткові зусилля можуть додати кілька байтів до складеної програми, що варто враховувати. Але це також врятує когось (можливо, і майбутнього ви) десь між годиною та днем ​​непродуктивного чухання голови.


Оновлення: описана вище ситуація, тобто захист від значень, доданих до перерахунку в більш пізній час, також може потрапити в компілятор. Clang (і я думаю, що GCC) за замовчуванням видасть попередження, якщо ви переключите перелічений тип, але у вас немає випадку, який охоплює всі можливі значення в перерахунку. Так, наприклад, якщо ви виймете defaultкорпус зі свого перемикача та додасте нове значення MyBazдо перерахунку, ви отримаєте попередження, яке говорить:

Enumeration value 'MyBaz' not handled in switch

Дозволити компілятору виявити незакриті випадки - це значною мірою усуває потребу в тій недосяжній defaultсправі, яка надихнула насамперед ваше запитання.


2
Гаразд, ти переконав мене :) Мені просто доведеться приймати вм’ятину в своїх номерах коду.
sd

@st Немає причини, щоб ви не могли протестувати цей код. Просто зробіть тестову збірку, яка умовно компілює додаткове значення у вашому перерахунку, а потім напишіть одиничний тест, який його використовує. Можливо, це не ідеально, але, мабуть, це не єдиний випадок, коли потрібно перевірити код, до якого зазвичай ніколи не дістанеться.
Калеб

Або ви присвоюєте не-перерахувальне значення своєму типу enum і використовуєте це.
Мауг каже, що повернемо Моніку

5

Я просто говорив з колегою про це також сьогодні вранці - це справді прикро, але я вважаю, що обробляти дефолт потрібно з безпеки з двох причин:

По-перше, як зазначає ваш колега, це в майбутньому підтверджує код проти нових значень, що додаються до перерахунків. Це може чи не здається можливим, але воно завжди є.

Що ще важливіше, залежно від мови / компілятора, можливо, у вашій комутаційній змінній можуть бути значення, які не є членами перерахунку. Наприклад, в C #:

MyEnum myEnum = (MyEnum) 3; // This could come from anywhere, maybe parsed from text?
// ... code goes on for a while

switch ( myEnum )
{
    case MyEnum.A:
        // ... handle A case
        break;
    case MyEnum.B:
        // ... handle B case
        break;
}

// ... code that expects either A or B to have happened

Додавши просте case default:і кинувши виняток, ви захистили себе від цього дивного випадку, коли "нічого" не відбувається, але "щось" повинно було статися.

На жаль, в основному будь-коли я пишу заяву про перемикання більше, це тому, що я перевіряю випадки перерахунків. Я дуже хочу, щоб поведінка "кинути за замовчуванням" могла бути застосована самою мовою (принаймні, додавши ключове слово).


3

Додавання випадку за замовчуванням, навіть якщо ви ніколи не сподіваєтесь на його досягнення, може бути хорошою справою. Це налагодить налагодження набагато простіше, якщо ваш код викине виняток "Це не мало статися" одразу, а не пізніше в програмі, перекинувши якийсь загадковий виняток або повернувши несподівані результати без помилок.


2

Я кажу:

Спробуйте додати інший тип до MyEnum. Потім змініть цей рядок:

MyEnum myEnum = GetMyEnum();

до

MyEnum myEnum = SomethingElse;

Потім запустіть свій код із регістром за замовчуванням та без регістру за замовчуванням. Якій поведінці ви віддаєте перевагу?

Наявність випадку за замовчуванням також може бути корисним для захоплення NULLзначень та запобігання NullPointerExceptions.


-1

Якщо ви мали уявлення про те, як можна заощадити час мачу, наполягаючи на випадку за замовчуванням, вам не потрібно буде ставити питання. Мовчки нічого не робити в умовах помилки неприйнятно - ви мовчки ловите винятки, які ніколи не повинні відбуватися? Залишати "міни" для програмістів, які йдуть за вами, так само неприпустимо.

Якщо ваш код ніколи не буде змінено або змінено, і він на 100% вільний з помилок, не виходячи із випадку за замовчуванням.

Ада (дід надійних мов програмування) не збирає перемикач на enum, якщо тільки всі перерахунки не покриті або не буде обробника за замовчуванням - ця функція є в моєму списку бажань для кожної мови. Наш стандарт кодування Ada зазначає, що із вмиканням перерахунків, явним поводженням з усіма значеннями, без замовчування, є кращим способом вирішення цієї ситуації.


Чому всі -1?
mattnz

2
Я вас не -1, але я вважаю, що це буде через ваше ставлення;)
Friek
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.