Як використовувати спробу вилову для обробки винятків - найкраща практика


201

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

try
{
  //do something
}
catch
{
  //Do nothing
}

або іноді вони записують інформацію про реєстрацію у файли журналу, такі як наступний try catchблок

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);
}

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

Будь ласка, дайте мені поради.


128
Знімок №1 становить 99,999% часу неприйнятного.
леппі

22
Відображення виключення безпосередньо користувачеві ніколи не є хорошою ідеєю, головним чином, з двох причин: 1. якщо це звичайні користувачі, він буде дратуватися повідомленням про помилку читання, яке повідомляє про нього дуже мало. 2. якщо він, так званий, хакер (и), він може отримати корисну інформацію. Найкраща практика, IMO, - реєструвати винятки та показувати дружнє повідомлення про помилку.
Лері

4
@leppie Якщо що - то несподіване відбувається (наприклад , NullReferenceчи ArgumentNullщо не є частиною потоку додатки) , це означає , що є помилка , яка повинна бути виправлена таким чином їх реєстрації допоможе налагодження коду набагато швидше.
Лері

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

12
@Toan, добре, якщо це пакетна робота, я ловлю на верхньому рівні (Main), щоб увійти в систему, а потім повторюю, щоб увімкнути сигнал про те, що робота припиняється аномально. Якщо це веб-додаток, я пускаю мітку про виняток на глобальний обробник, здійснює реєстрацію, а потім перенаправляю користувача на екран помилок. Ваш сценарій використання випадку диктує, що ви робите з цим винятком після того, як ви ввійшли в систему або обробляли іншим способом.
Ентоні Пеграм

Відповіді:


300

Моя стратегія обробки винятків:

  • Щоб зловити всі необроблені винятки , підключившись до пункту Application.ThreadException event, тоді вирішіть:

    • Для програми інтерфейсу користувача: надіслати його користувачеві із вибаченням (winforms)
    • Для програми Сервіс або Консоль: увійдіть у файл (службу чи консоль)

Тоді я завжди додаю кожен шматок коду , який виконується зовні в try/catch:

  • Усі події, запущені інфраструктурою Winforms (Завантажити, натиснути, вибране змінено ...)
  • Усі події, запущені сторонніми компонентами

Тоді я додаю в "спробувати / зловити"

  • Усі відомі мені операції можуть не працювати весь час ( операції вводу- виводу, розрахунки з потенційним нульовим поділом ...). У такому випадку я кидаю нове, ApplicationException("custom message", innerException)щоб слідкувати за тим, що насправді сталося

Крім того, я намагаюся правильно сортувати винятки . Є винятки, які:

  • потрібно негайно показати користувачеві
  • вимагати додаткової обробки, щоб скласти речі, коли вони трапляються, щоб уникнути каскадних проблем (тобто: поставити .EndUpdate у finallyрозділі під час TreeViewзаливки)
  • користувачеві це байдуже, але важливо знати, що сталося. Тому я завжди реєструю їх:

    • У журналі подій
    • або у файлі .log на диску

Доброю практикою є розробка деяких статичних методів для обробки виключень у програмах обробників помилок верхнього рівня.

Я також змушую себе намагатися:

  • Пам’ятайте, що ВСІ винятки піднімаються до верхнього рівня . Не обов’язково скрізь ставити обробники винятків.
  • Функції для багаторазового використання або глибокі виклики не потребують відображення або журналу винятків: вони або автоматично перемикаються, або перезавантажуються якимись спеціальними повідомленнями в моїх обробниках виключень.

Отже, нарешті:

Погано:

// DON'T DO THIS, ITS BAD
try
{
    ...
}
catch 
{
   // only air...
}

Марно:

// DONT'T DO THIS, ITS USELESS
try
{
    ...
}
catch(Exception ex)
{
    throw ex;
}

Спроба, нарешті, без улову, цілком справедлива:

try
{
    listView1.BeginUpdate();

    // If an exception occurs in the following code, then the finally will be executed
    // and the exception will be thrown
    ...
}
finally
{
    // I WANT THIS CODE TO RUN EVENTUALLY REGARDLESS AN EXCEPTION OCCURED OR NOT
    listView1.EndUpdate();
}

Що я роблю на найвищому рівні:

// i.e When the user clicks on a button
try
{
    ...
}
catch(Exception ex)
{
    ex.Log(); // Log exception

    -- OR --

    ex.Log().Display(); // Log exception, then show it to the user with apologies...
}

Що я роблю в деяких функціях, що називаються:

// Calculation module
try
{
    ...
}
catch(Exception ex)
{
    // Add useful information to the exception
    throw new ApplicationException("Something wrong happened in the calculation module :", ex);
}

// IO module
try
{
    ...
}
catch(Exception ex)
{
    throw new ApplicationException(string.Format("I cannot write the file {0} to {1}", fileName, directoryName), ex);
}

Існує багато спільного з обробкою винятків (користувальницькі винятки), але правил, які я намагаюся мати на увазі, достатньо для простих програм, які я роблю.

Ось приклад методів розширень зручним способом обробляти винятки. Вони реалізовані так, як їх можна зв'язати разом, і додати власну обробку винятків винятків дуже просто.

// Usage:

try
{
    // boom
}
catch(Exception ex)
{
    // Only log exception
    ex.Log();

    -- OR --

    // Only display exception
    ex.Display();

    -- OR --

    // Log, then display exception
    ex.Log().Display();

    -- OR --

    // Add some user-friendly message to an exception
    new ApplicationException("Unable to calculate !", ex).Log().Display();
}

// Extension methods

internal static Exception Log(this Exception ex)
{
    File.AppendAllText("CaughtExceptions" + DateTime.Now.ToString("yyyy-MM-dd") + ".log", DateTime.Now.ToString("HH:mm:ss") + ": " + ex.Message + "\n" + ex.ToString() + "\n");
    return ex;
}

internal static Exception Display(this Exception ex, string msg = null, MessageBoxImage img = MessageBoxImage.Error)
{
    MessageBox.Show(msg ?? ex.Message, "", MessageBoxButton.OK, img);
    return ex;
}

98
catch(Exception ex) { throw ex; }у C # гірше надмірного (незалежно від типу винятку, який ви ловите). Для повторного скидання використовуйте throw;. З першим, виняток буде виглядати так, що він походить від вашого, throw exтоді як з другим, він буде належним чином походити з оригінального throwтвердження.
CVn

2
Чому ви підключаєте Application.ThreadExceptionподію і обробляєте кожен виняток символом a catch(Exception ex) {ex.Log(ex);}. Я, мабуть, погоджуюся, що перший - це відмінна практика, але останній додає ризику дублювання ваших журналів помилок і приховує, що виняток стався. Також throw exдуже погано.
Кіт

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

3
Чудова і конструктивна відповідь, найбільше мені сподобалась фраза Тільки повітря :) І дякую за Application.ThreadExceptionподію, я цього не знала, дуже корисна.
Махді Тахсілдарі


61

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

Існує 3 обставини, коли використання try-catchсенсу має сенс.

  1. Завжди поводьтеся з відомими винятками як можна нижче. Однак, якщо ви очікуєте винятку, зазвичай краще спочатку перевірити його. Наприклад, виключення синтаксичного розбору, форматування та арифметики майже завжди краще обробляються спочатку логічними перевірками, а не конкретними try-catch.

  2. Якщо вам потрібно зробити щось за винятком (наприклад, увійти в журнал або скасувати транзакцію), тоді повторно киньте виняток.

  3. Завжди обробляйте невідомі винятки якнайбільше - єдиний код, який повинен споживати виняток, а не перекидати його, повинен бути інтерфейсом користувача або загальнодоступним API.

Припустимо, ви підключаєтесь до віддаленого API, тут ви знаєте, що слід очікувати певних помилок (і виправити це за тих обставин), тож це випадок 1:

try 
{
    remoteApi.Connect()
}
catch(ApiConnectionSecurityException ex) 
{
    // User's security details have expired
    return false;
}

return true;

Зауважте, що жодних інших винятків не спіймано, оскільки їх не передбачається.

Тепер припустимо, що ви намагаєтесь щось зберегти в базі даних. Ми повинні повернути її назад, якщо вона не працює, тому у нас є випадок 2:

try
{
    DBConnection.Save();
}
catch
{
    // Roll back the DB changes so they aren't corrupted on ANY exception
    DBConnection.Rollback();

    // Re-throw the exception, it's critical that the user knows that it failed to save
    throw;
}

Зауважте, що ми повторно кидаємо виняток - код вище все ще повинен знати, що щось не вдалося.

Нарешті, у нас є інтерфейс користувача - тут ми не хочемо мати абсолютно незроблених винятків, але ми також не хочемо їх приховувати. Тут ми маємо приклад випадку 3:

try
{
    // Do something
}
catch(Exception ex) 
{
    // Log exception for developers
    WriteException2LogFile(ex);

    // Display message to users
    DisplayWarningBox("An error has occurred, please contact support!");
}

Однак більшість фреймворків API або UI мають загальні способи ведення випадку 3. Наприклад, ASP.Net має жовтий екран помилок, який скидає деталі про винятки, але це може бути замінено більш загальним повідомленням у виробничому середовищі. Дотримуватися цих найкращих практик, оскільки це економить багато коду, а також тому, що реєстрація помилок та відображення помилок повинні бути конфігураційними рішеннями, а не жорстко кодованими.

Це все означає, що випадок 1 (відомі винятки) та випадок 3 (разова обробка інтерфейсу користувача) мають кращі зразки (уникайте очікуваної помилки або помилки вручну, що переходить до інтерфейсу).

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

Наприклад, припустимо, у вас є широкомасштабний додаток ASP.Net. Реєстрація помилок може здійснюватися через ELMAH , відображення помилок може бути інформаційним YSoD локально та приємним локалізованим повідомленням у виробництві. Підключення до бази даних можуть здійснюватися через сфери та usingблоки транзакцій . Вам не потрібен один try-catchблок.

TL; DR: Найкраща практика - це взагалі не використовувати try-catchблоки.


4
@Jorj, ви повинні прочитати весь пост, і якщо ви все ще не погоджуєтесь, можливо, було б більш конструктивно протиставити один із моїх підтверджуючих аргументів, а не просто заявляти, що ви не любите мого висновку. Майже завжди є кращий зразок, ніж try-catch- це може (дуже часто) бути корисним, і я не стверджую, що ви ніколи не повинні їх використовувати, але в 99% часу є кращий спосіб.
Кіт

Найкраща відповідь на даний момент - майже кожен тип розробки .net має якусь рукодільницю, яка набагато краще підходить для боротьби з винятками на глобальному рівні, що робить їх набагато простішим послідовно поводитися з ними, а також набагато легше просто пускати його на удар в розробці (чому б хто-небудь хотів викопати файл журналу для сліду стека ??) @Kieth, я б привів із вашим TLDR і додав у деякі приклади глобальних обробників (наприклад, ThreadException, Application_Error тощо).
Очевидно, що вловлюють СПЕЦІФІЧНІ

34

Виняток - помилка блокування .

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

Якщо помилка блокується , киньте виняток. Після того, як виняток уже кинуто, його не потрібно приховувати, оскільки він винятковий; повідомте користувача про це (ви повинні переформатувати весь виняток на щось корисне для користувача в інтерфейсі).

Ваша робота як розробник програмного забезпечення - домагатися запобігання виняткових випадків, коли деякі параметри або ситуація виконання може закінчитися винятком. Тобто винятки не слід вимкнути, але їх слід уникати .

Наприклад, якщо ви знаєте, що деякий цілочисельний вхід може мати недійсний формат, використовуйте int.TryParseзамість int.Parse. Є маса випадків, коли ви можете це зробити замість того, щоб просто сказати "якщо це не вдасться, просто киньте виняток".

Кидати винятки дорого.

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

  • ASP.NET: Global.asax Application_Error
  • Інші: AppDomain.FirstChanceException подія .

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

Для решти випадків:

  • Намагайтеся уникати винятків.
  • Якщо це неможливо: обробники виключень з першої ж можливості.
  • Або використовуйте аспект PostSharp (AOP).

Відповідаючи на @thewhiteambit на коментар ...

@thewhiteambit сказав:

Винятки не є Fatal-помилками, вони є винятками! Іноді вони навіть не є Помилками, але вважати їх фатальними помилками - це абсолютно помилкове розуміння того, що таке Винятки.

Перш за все, як виняток не може бути навіть помилкою?

  • Немає підключення до бази даних => Виняток.
  • Недійсний формат рядка для розбору на виняток type =>
  • Спроба розбору JSON і в той час як введення насправді не JSON => виняток
  • Аргумент nullпід час очікування об'єкта => виняток
  • Деяка бібліотека має помилку => кидає несподіваний виняток
  • Існує розеткове з'єднання, і воно відключається. Потім ви намагаєтесь надіслати повідомлення => виняток
  • ...

Ми можемо перерахувати 1k випадків, коли буде викинуто виняток, і зрештою, будь-який із можливих випадків буде помилкою .

Виняток - помилка, оскільки наприкінці дня це об’єкт, який збирає діагностичну інформацію - у ньому є повідомлення, і це відбувається, коли щось піде не так.

Ніхто не кидає виняток, коли немає виняткових випадків. Виняток має бути блокуванням помилок, тому що після їх викиду, якщо ви не намагаєтеся потрапити до використання try / catch та винятку для здійснення потоку управління, вони означають, що ваша програма / послуга припинять операцію, що вступила у винятковий випадок .

Також я пропоную всім перевірити невдалу парадигму, опубліковану Мартіном Фаулером (написану Джимом Шор) . Ось як я завжди розумів, як поводитися з винятками, ще до того, як я до цього документа потрапив.

[...] вважати їх Fatal-Errors є абсолютно помилковим розумінням того, що таке винятки.

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

Більше відповідей про проблеми @thewhiteambit

Наприклад, у випадку відсутності підключення до бази даних програма може винятково продовжувати запис у локальний файл та надсилати зміни до бази даних, як тільки вона знову буде доступна. Ваш недійсний кастинг рядка до числа може бути спробуваний знову розібратися з локальною інтерпретацією мови на винятку, як, наприклад, при спробі англійської мови за замовчуванням Parse ("1,5") не вдалося, і ви спробуєте її знову з німецькою інтерпретацією, яка повністю добре, оскільки ми використовуємо кому замість точки як роздільник. Ви бачите, що ці Винятки не повинні навіть блокуватись, вони потребують лише певної обробки винятків.

  1. Якщо ваш додаток може працювати в автономному режимі без збереження даних у базі даних, не слід використовувати винятки , оскільки реалізація потоку управління try/catchрозглядається як антидіаграма. Робота в режимі офлайн - це можливий випадок використання, тому ви впроваджуєте потік управління, щоб перевірити, чи доступна база даних чи ні, ви не чекаєте, поки вона недоступна .

  2. The розбору - це також очікуваний випадок ( не ВИКЛАДНИЙ СЛУЧАЙ ). Якщо ви цього очікуєте, ви не використовуєте винятків для контролю потоку! . Ви отримуєте від користувача деякі метадані, щоб знати, яка його культура, і ви використовуєте для цього формати! .NET також підтримує це та інші середовища, і виняток, оскільки форматування чисел потрібно уникати, якщо ви очікуєте використання програми / послуги, пов’язаної з культурою .

Неопрацьоване виняток зазвичай стає помилкою, але самі винятки не є codeproject.com/Articles/15921/Not-All-Exceptions-Are-Errors

Ця стаття є лише думкою чи точкою зору автора.

Оскільки Вікіпедія може бути лише думкою авторів (артикулів), я б не сказав, що це догма , але перевірте, що в статті " Кодування за винятком" йде десь у якомусь абзаці:

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

Тут також десь сказано:

Неправильне використання виключень

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

Чесно кажучи, я вважаю, що програмне забезпечення не може бути розроблене, не сприймаючи справи серйозно. Якщо ви знаєте, що ...

  • Ваша база даних може перейти в офлайн ...
  • Деякі файли можна заблокувати ...
  • Можливо, деякі формати не підтримуються ...
  • Деякі перевірки домену можуть не вдатися ...
  • Ваш додаток має працювати в режимі офлайн ...
  • незалежно від випадку використання ...

... ви не будете використовувати для цього винятки . Ви б підтримали ці випадки використання, використовуючи регулярний контрольний потік.

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

З іншого боку, і, нарешті, іноді ви охоплюєте виняткові випадки, кидаючи очікувані винятки , але ви не кидаєте їх для здійснення потоку контролю. Ви робите це, тому що хочете повідомити верхні шари, що ви не підтримуєте певний регістр використання, або ваш код не працює з деякими заданими аргументами або даними / властивостями середовища.


6

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

Винятки та журнали - це ви, розробник, а не ваш кінцевий користувач. Розуміння правильної справи, коли ви ловите кожен виняток, набагато краще, ніж просто застосування якогось золотого правила чи покладання на безпечну мережу.

Бездумне кодування є ТІЛЬКИ видом неправильного кодування. Той факт, що ви відчуваєте, що є щось краще, що можна зробити в тих ситуаціях, свідчить про те, що ви інвестуєте в хороше кодування, але уникайте спроб закреслити якесь загальне правило в цих ситуаціях і зрозуміти причину того, що кинути в першу чергу і що ви можете зробити, щоб відновитися після цього.


6

Я знаю, що це давнє запитання, але тут ніхто не згадував статтю MSDN, і саме цей документ насправді очистив для мене, MSDN має дуже хороший документ щодо цього, вам слід вчинити винятки, коли такі умови справджуються:

  • Ви добре розумієте, чому може бути викинуто виняток, і ви можете реалізувати специфічне відновлення, наприклад, спонукання користувача ввести нове ім'я файлу, коли ви ловите об’єкт FileNotFoundException.

  • Ви можете створити і викинути новий, більш конкретний виняток.

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch(System.IndexOutOfRangeException e)
    {
        throw new System.ArgumentOutOfRangeException(
            "Parameter index is out of range.");
    }
}
  • Ви хочете частково обробити виняток, перш ніж передавати його для додаткового керування. У наступному прикладі блок лову використовується для додавання запису до журналу помилок перед повторним викидом винятку.
    try
{
    // Try to access a resource.
}
catch (System.UnauthorizedAccessException e)
{
    // Call a custom error logging procedure.
    LogError(e);
    // Re-throw the error.
    throw;     
}

Я б запропонував прочитати весь розділ " Виключення та обробку винятків ", а також кращі практики для виключень .


1

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


1

За винятком я намагаюсь:

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

Тоді я намагаюся зловити залишилися винятки і записувати їх. Якщо можливо, дозвольте виконання коду, інакше попередити користувача про те, що сталася помилка, і попросіть його надіслати повідомлення про помилку.

У коді щось подібне:

try{
    //Some code here
}
catch(DivideByZeroException dz){
    AlerUserDivideByZerohappened();
}
catch(Exception e){
    treatGeneralException(e);
}
finally{
    //if a IO operation here i close the hanging handlers for example
}

1
Ділення на нульові винятки тощо подібне краще вирішувати, попередньо перевіривши 0чисельник, а не a try-catch. Також навіщо тут ловити загальне Exception? Вам краще пускати помилку, ніж боротися з нею тут у всіх випадках, коли ви цього не очікуєте.
Кіт

Читайте краще, що я написав на прикладі, який я наводив - помічайте "не в аргументах". Звичайно, будь-який калькулятор повинен перевірити дані аргументи. Те, що я говорив, було про середні кроки. У цей момент перевірка аргументу користувача вже відбулася. Також у деяких програмах краще уникати винятків, щоб вибухнути. Деякі додатки повинні трактувати винятки мовчки, де інші повинні трактувати винятки як помилки. Приклад веб-сервера повинен працювати навіть у випадках, коли трапляються винятки, коли медичне програмне забезпечення (наприклад, рентгенівські апарати) повинно бути скасовано, коли виникають винятки.
Sorcerer86pt

Жодна програма ніколи не повинна поводитися з винятками мовчки. Інколи у вас є виняток, який може обробляти код, але таке використання повинно бути як рідкісним, так і специфічним для очікуваного винятку. Ваш приклад веб-сервера поганий - він повинен мати налаштування конфігурації, які дозволяють вам вибирати спосіб реєстрації помилок та відображати їх з деталізацією або просто на сторінці HTTP 500, але вони ніколи не повинні мовчки ігнорувати помилки.
Кіт

Я намагаюся розібратися, що насправді мотивує людей додавати ще один синонім «гото». Але що стосується поділу на нуль, то це був би ЄДИН виняток, який я можу бачити, що виправдовує мовне вдосконалення. Чому? Оскільки цілком може бути випадок, що А) нуль статистично є нескінченно малим у вашому наборі даних, і В) використання (дозволення) винятку може бути набагато ефективнішим, оскільки виконання ділення - це один із способів перевірити нульовий дільник. Коли A і B вірні, середнє виконання вашої програми буде швидше, використовуючи виняток, і воно може бути навіть меншим.
Майк Лейтон

1

Другий підхід - хороший.

Якщо ви не хочете показувати помилку і плутати користувача програми, показуючи виняток виконання (тобто помилку), яке не пов’язане з ними, то просто помилка в журналі і технічна команда може шукати проблему та вирішувати її.

try
{
  //do some work
}
catch(Exception exception)
{
   WriteException2LogFile(exception);//it will write the or log the error in a text file
}

Я рекомендую перейти до другого підходу для всієї вашої програми.


2
Другий підхід не показує користувачеві, ніж сталася помилка - наприклад, якщо вони зберігали щось, вони не знали б, що це вийшло з ладу. catchблоки завжди повинні або закликати throwперемикати виняток увімкнено, або повертати щось / відображати щось, що повідомляє користувачеві, що дія не вдалося. Ви хочете отримати виклик підтримки, коли вони не зможуть зберегти, що б там не було, а не через 6 місяців, коли вони намагаються отримати його і не можуть його знайти.
Кіт

0

Залишати порожній блок лову - це гірше. Якщо виникла помилка, найкращий спосіб вирішити її:

  1. Увійдіть у файл \ базу даних тощо.
  2. Спробуйте виправити це на ходу (можливо, спробуйте альтернативний спосіб виконання цієї операції)
  3. Якщо ми не можемо це виправити, сповістіть користувача, що є якась помилка, і звичайно перервіть операцію

0

Для мене поводження з винятком можна розглядати як правило бізнесу. Очевидно, перший підхід неприйнятний. Другий - кращий, і це може бути на 100% правильний спосіб, якщо контекст так говорить. Зараз, наприклад, ви розробляєте Outlook Addin. Якщо ви додаєте, що викидає необроблений виняток, користувач Outlook може це знати, оскільки прогноз не знищить себе через те, що один плагін не вдався. І вам важко зрозуміти, що пішло не так. Тому другий підхід у цьому випадку, для мене, є правильним. Окрім реєстрації винятку, ви можете вирішити відображати повідомлення про помилку користувачеві - я вважаю це діловим правилом.


0

Найкраща практика - кинути виняток, коли виникає помилка. Тому що сталася помилка і її не слід приховувати.

Але в реальному житті у вас може виникнути кілька ситуацій, коли ви хочете це приховати

  1. Ви покладаєтесь на сторонній компонент і хочете продовжити програму в разі помилки.
  2. У вас є діловий випадок, який потрібно продовжувати у випадку помилки

6
Ні . Є НЕ кидати Exception. Колись. Введіть відповідний підклас Exceptionвсього, що вам потрібно, але ніколи, Exceptionоскільки це не дає абсолютно ніякої смислової інформації. Я висловлююсь не можу бачити сценарій, коли має сенс кинути, Exceptionале не його підклас.
CVn


0

Аргументи catchбез будь-яких просто їдять виняток і не приносять користі. Що робити, якщо трапиться смертельна помилка? Немає способу дізнатися, що сталося, якщо використовувати ловку без аргументів.

Виписка про вилов має містити більш конкретні винятки, як-от, FileNotFoundExceptionа потім на самому кінці ви повинні вловлювати Exceptionякий-небудь інший виняток і записувати їх.


Чому генерал catch(Exception)в кінці? Якщо ви цього не очікуєте, то завжди найкраще передати його до наступного шару.
Кіт

1
@Keith так, ти маєш рацію ... немає сенсу ловити винятки, яких ти не очікуєш, але ти можеш зробити загальний виняток для цілей реєстрації ..
Anirudha

0

Іноді потрібно обробляти винятки, які нічого не говорять користувачам.

Мій шлях такий:

  • Виловлювати виключення, що не враховуються, на рівні програми (наприклад, у global.asax) за критичні винятки (додаток не може бути корисним). Ці викриття я не ловлю на місці. Просто введіть їх на рівні додатків і нехай система виконує свою роботу.
  • Ловіть "на місці" і показуйте корисну інформацію користувачеві (введено неправильне число, не можна розбирати).
  • Ловіться на місці і не робіть нічого при граничних проблемах, таких як "Я буду перевіряти інформацію про оновлення на задньому плані, але служба не працює".

Це, безумовно, не повинно бути найкращою практикою. ;-)


0

Я можу вам щось сказати:

Знімок №1 неприйнятний, оскільки він ігнорує виняток. (це ковтає так, ніби нічого не сталося).

Тому не додайте блок лову, який нічого не робить, або просто переростає.

Блок лову повинен додати деяке значення. Наприклад, вихідне повідомлення кінцевому користувачеві або помилка журналу.

Не використовуйте виняток для логіки програми звичайного потоку. Наприклад:

наприклад, перевірка вводу. <- Це не дійсна виняткова ситуація, скоріше слід написати метод, IsValid(myInput);щоб перевірити, чи введений елемент введений чи ні.

Дизайн-код, щоб уникнути виключення. Наприклад:

int Parse(string input);

Якщо ми передамо значення, яке неможливо проаналізувати на int, цей метод буде викинутим і виключенням, замість цього ми можемо написати щось подібне:

bool TryParse(string input,out int result); <- цей метод повертає булеве вказівку, якщо синтаксичний аналіз був успішним.

Можливо, це трохи не виходить за рамки цього питання, але я сподіваюся, що це допоможе вам прийняти правильні рішення, коли мова йде про try {} catch(){}винятки та винятки.

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