Цілеспрямовано збільшити винятки для використання вилову


10

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

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

замість...

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        return null;
    }
}
catch(Exception ex)
{
    return null;
}

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


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

Відповіді:


12

Використання обробки винятків для контролю потоку відмовляється від Microsoft.

І круглий стіл на цю тему доступний.

Якщо говорити, C # підтримує це, і я вважаю, що це залежить від того, що виникає умова, чи є виняток найбільш прийнятною відповіддю.


1
Мене вражає, що подібні речі просто намагаються реально не використовувати події.
radarbob

@radarbob: Як події пов'язані з цим?

@grovesNL - кидання виключення в певний момент для виклику певного методу в блоці спіймання? Потрясіння як подія для мене.
radarbob

@radarbob: Це не подія. Є чимало випадків використання зразків, коли це було б використано, як це обговорюється у відповіді на круглому столі відповіді.

1
@radarbob Лише трохи уточнень, винятки були розроблені як спосіб сигналізувати абоненту про те, що щось сталося, з яким викликаним методом не вдається впоратися. Однак потрібно прослухати подію. Виняток - примусове переривання нормального потоку програми. Невиконаний виняток призведе до відмови всієї програми.

6

Показник ефективності, мабуть, незначний, як пояснено у цій відповіді .

Тож давайте підемо з думкою, що продуктивність не є проблемою. Ви кидаєте System.Exception, просто щоб перемістити виконання в catchпункт . Кидати котрий-небудь BadControlFlowThatShouldBeRewrittenException, мабуть, буде надмірно, хоча.

Розберемо це. Ми маємо:

  • Метод GetDataFromServer(назви методів повинні бути PascalCase в C #), який, можливо, може кинути виняток або повернути a bool.
  • Якщо результат був true, запустіть ProcessData.
  • Поверніться nullінакше.

Схоже, метод, де написаний цей код, просто робить занадто багато речей. GetDataFromServerповернення boolвиглядає як недолік дизайну, я б очікував, що цей метод поверне дані, отримані з сервера , IEnumerable<SomeType>які містять 0 і більше елементів - тобто щасливий шлях повертає n елементів, де n> 0 , не дуже щасливий шлях повертає 0 елементів, і нещасний шлях вибухає за незробленим винятком, що б там не було.

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

try
{
    var result = GetDataFromServer();
    return ProcessData(result);
}
catch
{
    return null;
}

Тут ви подивитесь ProcessDataі побачите, що він повторює resultі повертається, nullякщо в ньому немає жодного елемента IEnumerable.

Тепер чому метод повертається null? Сервер не працює? Чи є помилка в запиті? У рядку з'єднання використовуються неправильні облікові дані? Щоразу, коли ви GetDataFromServerвибухаєте за винятком, якого ви не очікуєте, ви ковтаєте його, засуваючи під килим і повертаючи nullзначення. Я рекомендую в цьому випадку вибирати конкретні винятки та реєструвати все інше; налагодження буде набагато простішим шляхом.

Із загальним catchзастереженням, яке не враховує винятку, діагностувати щось досить важко. Я б мінімум зробив це замість цього:

catch(Exception e)
{
    return null;
}

Тепер ви можете принаймні зламати та перевірити, eчи не піде щось не так.


TL; DR : Ні, кидання та вилучення винятків для контролю потоку не є хорошою ідеєю.


Ця відповідь точно показує, чому я намагався зберегти свій код загальним: я не хотів перераховувати всі винятки, які я фактично роблю у своєму коді; Я не хотів перераховувати фактичні назви методів; Я не хотів перераховувати декларацію методу; Я не хотів синтаксичних пропозицій. У мене було єдине запитання про те, чи нормально викидати винятки для контролю потоку, на що оперативно відповів B2K. Я був би радий обговорити це на мета.

3
Здається, це тоді повинно було бути питанням для програмістів. ми переглядаємо код, а не ідеї.
Малачі

2

у вашій першій відповіді є хіт про ефективність, який не повинен бути там.

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

коли ви виходите з оператора if, щоб увійти в оператор Catch, коли вам не потрібно робити вказівки перемикання коду, так би мовити.

якщо ви хочете return null; зробити це в операторі else, а не в уловленні, яке потрапляє після того, як викинуте з заяви.

Можливо, це не стосується Вашого Реального коду, але для Загального коду, який Ви йому надали, він застосовується.

Стандарти говорять, що ви не повинні цього робити.

Стандарти говорять, що ви повинні робити це так (знову ж таки на основі Загального коду, наведеного в ОП)

if (GetDataFromServer())
{
    return ProcessData();
}
else
{
    Return null
}

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

ви хочете бачити винятки, коли вони виникають, щоб ви могли виправити проблему, яка створює виняток.


1

Чому б не простіше:

if (!GetDataFromServer()) return null;
ProcessData();

Якщо обробник винятків буде існувати, він повинен бути в ProcessData ()


Чому б я не хотів передавати винятки ProcessData()на найвищий рівень?
гаїNL

@grovesNL Нічого корисного тут не робилося за винятком.
Лорен Печтел

1
Як так? Якщо ProcessData()викидає виняток зараз, це не обробляється. Я хочу, щоб це було return nullна цьому рівні, якщо ProcessData()кидає виняток, не змінюючи ProcessData()себе.
гаїNL
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.