C # try {} catch {} - PullRequest
       72

C # try {} catch {}

10 голосов
/ 21 января 2010

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

        catch (ArgumentNullException e)
        {
            OnNetworkEvents eventArgs = new OnNetworkEvents("Network Unavailable", e.Message);
            OnUpdateNetworkStatusMessage(this, eventArgs);
        }
        catch (EncoderFallbackException e)
        {
            OnNetworkEvents eventArgs = new OnNetworkEvents("Network Unavailable", e.Message);
            OnUpdateNetworkStatusMessage(this, eventArgs);
        }
        catch (SocketException e)
        {
            OnNetworkEvents eventArgs = new OnNetworkEvents("Network Unavailable", e.Message);
            OnUpdateNetworkStatusMessage(this, eventArgs);
        }
        catch (ArgumentOutOfRangeException e)
        {
            OnNetworkEvents eventArgs = new OnNetworkEvents("Network Unavailable", e.Message);
            OnUpdateNetworkStatusMessage(this, eventArgs);
        }
        catch (ObjectDisposedException e)
        {
            OnNetworkEvents eventArgs = new OnNetworkEvents("Network Unavailable", e.Message);
            OnUpdateNetworkStatusMessage(this, eventArgs);
        }

Мне просто интересно, смогу ли я заменить этот повторяющийся код одним:

catch (Exception e) { handle here}

будет ли это работать?

Еще раз спасибо.

Ответы [ 11 ]

22 голосов
/ 21 января 2010

Нет, никогда не перехватывает System.Exception . Сегодня я чувствую себя побитой, но я не могу этого подчеркнуть. Вы не можете справиться с OutOfMemoryException или AccessViolationException, поэтому не ловите его!

Что касается примера кода, я сильно сомневаюсь, что исключение ArgumentNullException или ArgumentOutOfRange будет соответствовать сетевой ошибке. Если это так, то, скорее всего, это означает, что компонент, который действительно должен перехватить это исключение, не является.

«Отказоустойчивость» не означает «есть каждое исключение, чтобы приложение не зависало» - это означает, что нужно знать, что может пойти не так, и правильно обрабатывать .

16 голосов
/ 21 января 2010

Как правило, не поймать System.Exception. Это плохая идея и плохой запах кода, указывающий на неспособность понять цель исключений. Я считаю, что это результат веры разработчика, что исключения являются ошибкой, а не кодом, который вызвал исключение.

Я постоянно вижу этот сбой в рабочем коде, и он неизменно маскирует реальные ошибки, поскольку допустимые и полезные исключения перехватываются и проглатываются, оставляя приложение в плохом состоянии. Это делает намного более сложным, чтобы отследить основную причину сбоя.

Поймать исключения, используя метод, который вы использовали здесь, более или менее правильный способ сделать это. Есть несколько вещей, которые вы можете улучшить, хотя:

  1. Обычно не рассматривайте ArgumentNullException или ArgumentOutOfRangeException как сбой сети во время выполнения (если это не так). Скорее, это следует рассматривать как логическую ошибку, которая приводит к сбою вашей программы как можно быстрее (чтобы вы могли проверить это с помощью отладчика как можно ближе к точке сбоя). Это часто означает, что вы вообще не поймаете ArgumentException.

  2. Подумайте об изучении иерархии исключений, чтобы найти подходящее базовое исключение, которое охватывает исключения, о которых вы пытаетесь сообщить. Например, (я не искал это), предположим, что три из все ваши исключения получены из SocketException. Вы могли бы сохранить некоторую типизацию, поймав SocketException вместо трех отдельных исключений. Однако делайте это только в том случае, если вы сообщаете о всех исключениях сокетов. (Это в основном более дисциплинированная версия вашей первоначальной попытки просто поймать Exception)

  3. Поскольку обе строки в каждом обработчике исключений идентичны, вы можете создать функцию для выполнения этих двух строк в одной строке обработчика . Типичный рефакторинг "не повторяй себя". Если вы хотите изменить способ сообщения об исключении, подумайте, насколько проще было бы изменить одну функцию, чем все эти отдельные обработчики.

  4. Практически любой значимый ввод / вывод (на ум приходят сеть и файл) повлечет за собой довольно значительную цепочку обработчиков исключений только потому, что так много всего может пойти не так. Просмотр большого количества сообщений об ошибках, связанных с вводом / выводом, которые могут дать сбой, не является анти-паттерном, но это может быть хорошим запахом кода. Как запах свежей сосны или свежеиспеченный хлеб. :)

3 голосов
/ 21 января 2010

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

Сохраните то, что у вас есть, и добавьте базовый регистр в конце:

catch (ArgumentNullException e) { ... }
catch (EncoderFallbackException e)  { ... }
catch (SocketException e) { ... }
catch (ArgumentOutOfRangeException e)  { ... }
catch (ObjectDisposedException e) { ... }
catch (Exception e)
{
    // not handled by above exceptions, do something if needed
    throw; // after doing what you need, re-throw it
}
3 голосов
/ 21 января 2010

Это наверняка поймает все исключения, но это может быть плохой практикой. Существуют некоторые исключения, которые будут скрыты или искажены, что значительно затруднит тестирование и отладку приложения.

2 голосов
/ 21 января 2010

Как и во всех предыдущих комментариях, вы должны перехватить все "известные" исключения с определенным блоком перехвата исключений и другие неизвестные или, что более уместно, все "несоответствующие" исключения с catch (Exception ex) { ... } или просто catch { ... }

Однако, как указано в вашем коде, вы обрабатываете все виды исключений одинаково. Таким образом, в этом конкретном случае выходные данные (то, что вы называете Fault Tolerance ) будут такими же, но производительность улучшится (поскольку среде выполнения не нужно сравнивать тип исключения с заданным списком типов).

Мораль истории: В этом конкретном случае используйте одну общую попытку. Но в целом избегайте такой привычки.

1 голос
/ 21 января 2010

Я только что прочитал сообщение в блоге на эту самую тему этим утром.

Вы можете сделать что-то подобное, упомянутое в комментариях к посту:

catch(Exception e){
    if(    e is ArgumentNullException 
        || e is EncoderFallbackException 
        || e is ...whatever 
    ){
      OnNetworkEvents eventArgs = new OnNetworkEvents("Network Unavailable", e.Message);
      OnUpdateNetworkStatusMessage(this, eventArgs);
    } else { throw; } 
}
1 голос
/ 21 января 2010

Будет перехватывать все исключения, которые наследуются от класса Exception. Если все они обрабатываются одинаково, вы можете сделать это, но не должны, поскольку вы не можете обрабатывать все исключения, унаследованные от исключения, одинаково.

1 голос
/ 21 января 2010

Да, это будет работать , но это не будет делать то же самое, поскольку будут исключены все исключения, а не только конкретные.

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

1 голос
/ 21 января 2010

Это будет работать, но также будет перехватывать исключения с нулевой ссылкой и любое другое случайное исключение, которое было сгенерировано.

0 голосов
/ 21 января 2010

IMO:

Поймать Exception было бы очень похоже на наличие методов с параметрами, которые никогда не являются более специфичными для класса, чем Object; Конечно, вы можете сделать это, но действительно ли это лучшее решение 9 из 10 раз?

То, что вы должны рассмотреть, чтобы упростить свой код, - это некоторые исключения Catch с наивысшим определением, которое уместно.

Например, в Java я бы

try{...}
catch( IOException e ) {...}

для перехвата всех исключений, связанных с IO.

Существует слишком много вещей, которые могут генерировать слишком много различных типов исключений, обычно вам следует избегать использования всеобъемлющего Exception.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...