Есть исключения в c # om nom nom - PullRequest
10 голосов
/ 07 октября 2010

Учитывая, что употребление исключений - это всегда плохо, а повторное создание исключения приводит к потере стека вызовов, как правильно переформулировать следующее?

Исключения в еде:

try
{
  … do something meaningful
}
catch(SomeException ex)
{
   // eat exception
}

Ответы [ 16 ]

29 голосов
/ 07 октября 2010
try
{
 ...
}
catch(SomeException e)
{
 //Do whatever is needed with e
 throw; //This rethrows and preserves call stack.
}
7 голосов
/ 07 октября 2010

Поймать и обработать определенные типы исключений.Хорошей практикой является , а не , просто перехват System.Exception.Надежная подпрограмма будет строго печатать исключения, которые она знает, как обрабатывать.

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

В зависимости от конкретного типа, вы можете или не можете сбросить его.Например, исключение синтаксического анализа ASP, выдаваемое на страницу ошибки, которая использует код, вызывающий исключение, вызовет бесконечный цикл.

try
{

}
catch( FileIOException )
{
    // unwind and re-throw as determined by the specific exception type
}
catch( UnauthorizedAccessException )
{
    // unwind and re-throw as determined by the specific exception type
}
catch( SomeOtherException )
{
    // unwind and re-throw as determined by the specific exception type
}
catch( Exception )
{
   // log and re-throw...add your own message, capture the call stack, etc.

   // throw original exception
   throw;

   // OR, throw your own custom exception that provides more specific detail and captures
   // the original exception as the inner exception
   throw new MyStronglyTypedException();
}
finally
{
     // always clean up
}
5 голосов
/ 08 октября 2010

Большинство людей думают, что есть зло / подавлять исключения, особенно в случае с ловушками, совершенно зло.(По иронии судьбы, они используют ответ «поймай все» «не используй ловушки, это зло» :-).Я не понимаю религиозного рвения, с которым люди разделяют эту точку зрения, потому что, если использовать разумно , в этом подходе нет ничего плохого.

  • В моей книгев худшем случае моя программа катастрофически завершает работу -> это создает очень несчастного клиента с ситуацией полной потери данных.Исключение необработанное гарантированно будет вызывать это каждый раз.Поэтому отсутствие обработки исключения статистически более опасно , чем любой риск нестабильности, который может возникнуть, если исключение исключено.В свете этого все, что мы можем разумно сделать для защиты от необработанного исключения, является хорошей вещью.

  • Многие люди, похоже, забывают о том, что catch-all могут часто обрабатывать any исключение правильно, даже если они не знают деталей того, что было исключением.Под этим я подразумеваю, что они могут гарантировать, что состояние программы остается стабильным, и программа продолжает работать в рамках своих параметров проектирования.Или могут даже быть побочные эффекты, такие как пользователь, находящий кнопку не реагирующей, но он все равно не будет потерять какие-либо данные (т. Е. Постепенная деградация лучше, чем фатальная авария).Например, иногда вы хотите вернуть одно значение в случае успеха и значение по умолчанию, если вы потерпите неудачу по любой причине .Частью разработки кода является знание того, когда сообщать об ошибках пользователю, а когда исправлять проблему от его имени, чтобы его программа «просто работала».В этой ситуации хорошо продуманный универсальный подход часто является правильным инструментом для работы.

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

    • Если программист забывает документировать одно исключение, которое он может выбросить, я не буду знать, что мне нужно его перехватить, и мой код будет иметь уязвимость.не в курсе.
    • Если кто-то обновит метод, чтобы он выбрасывал новый тип исключения, это новое исключение могло бы волновать стек вызовов, пока не достигнет моего кода.Но мой код не был создан для обработки исключения.Не говорите мне, что библиотеки, которые я вызываю, никогда не изменятся.
    • Каждый тип исключения, который вы обрабатываете специально, - это еще один путь кода, который нужно протестировать.Это значительно увеличивает сложность тестирования и / или риск того, что сломанный бит обработки кода может остаться незамеченным.
  • Представление, основанное на представлении «подавление зла», заключается в том, чтовсе исключения представляют нестабильность или ошибку - но во многих случаях программисты используют исключения, чтобы возвращать чуть больше информации о состоянии.Например, FileNotFound.Программист, пишущий код ввода / вывода файла, решил от моего имени , что отсутствующий файл является фатальной ошибкой.И это может быть.Я должен поймать это и решить, что на самом деле это обычная и совершенно нормальная или ожидаемая ситуация.В большинстве случаев подавление исключений необходимо для того, чтобы просто остановить чье-либо «решение» о вынесении моего заявления.Старый подход простого игнорирования кодов возврата ошибок не всегда был плохим, особенно учитывая количество усилий, которое требуется для отлова и подавления бесчисленных исключений «статуса», о которых идет речь.

Хитрость в том, чтобы молча есть / подавлять исключения, просто быть уверенным, что это правильный способ их обработки.(И во многих случаях это не так).Так что может не потребоваться рефакторинг вашего примера кода - это не может быть плохим джиу.

3 голосов
/ 07 октября 2010

Все зависит от того, где живет код.

В глубине системы? Если это так, то я бы понял, что в продукте должна существовать некоторая форма стандартной обработки ошибок, если не нужно.

Если он, например, находится на стороне представления, он может не иметь никакого значения для кого-либо, кроме кода, и в этом случае может потребоваться разместить дополнительную логику в блоке finally.

Или пусть он скатывается в гору и не заворачивает его в ловушку, если вы все равно не собираетесь делать ничего полезного в добыче.

… do something meaningful
2 голосов
/ 07 октября 2010

В общем, не стоит ловить общее Exception, если вы не справитесь с этим. Я думаю, что правильный ответ - это комбинация ответов Тима и Джошуа. Если есть определенные исключения, которые вы можете обработать и сохранить в хорошем состоянии, например FileNotFoundException, вы должны перехватить их, обработать их и двигаться дальше, как показано здесь:

try
{
    // do something meaningful
}
catch(FileNotFoundException)
{
    MessageBox.Show("The file does not exist.");
}

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

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

try
{
    BeginTransaction();

    // do something meaningful

    CommitTransaction();
}
catch(FileNotFoundException)
{
    MessageBox.Show("The file does not exist.");
    AbortTransaction();
}
catch(Exception)
{
    AbortTransaction();
    throw;                  // using "throw;" instead of "throw ex;" preserves
                            // the stack trace
}
2 голосов
/ 07 октября 2010

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

Существует три способа «перебросить» исключение:

catch (Exception ex)
{
   throw;
}

Выше сохраняется стек вызовов исходного исключения.

catch (Exception ex)
{
   throw ex;
}

Вышеперечисленное съедает исходную цепочку исключений и начинает новую.

catch (Exception ex)
{
   throw new MyException("blah", ex);
}

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

2 голосов
/ 07 октября 2010

Ваш код может быть переписан (исключение), например:

try
{
  … do something meaningful
}
catch
{
   // eat exception
}

Но я не понимаю, что вы хотите сделать путем рефакторинга !!

Редактировать:

Перебрасывание с использованием throw; не всегда работает.Читать это -> http://weblogs.asp.net/fmarguerie/archive/2008/01/02/rethrowing-exceptions-and-preserving-the-full-call-stack-trace.aspx

1 голос
/ 07 октября 2010

Измените его на:

// No try
{ 
   … do something meaningful 
} 
// No catch

и разрешить обработку исключения в главном цикле.

0 голосов
/ 07 октября 2010

Одна из основных проблем с иерархией исключений состоит в том, что исключения классифицируются на основе того, что произошло, а не на основе состояния системы. Некоторые исключения означают, что «функция не может выполнить свою задачу, но она также не нарушает состояние системы». Другие означают «Беги за свою жизнь! Вся система тает!» Во многих случаях было бы вполне уместно для подпрограммы, которая могла бы обработать сбой вызванного метода, чтобы проглотить все без исключения исключения первого типа; в других случаях такие исключения должны быть переброшены таким образом, который указывает на возможное повреждение состояния (например, из-за сбоя в операции, необходимой для сброса состояния системы; даже если попытка выполнить эту операцию ничего не мешала, факт что состояние не было сброшено, значит оно повреждено).

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

0 голосов
/ 07 октября 2010

Иногда лучше не иметь дело с исключениями, если вы действительно не хотите иметь дело с дополнительной ответственностью, которая сопровождает исключения. Например, вместо того, чтобы ловить NullReferenceException, почему бы просто не убедиться, что объект существует, прежде чем пытаться что-то с ним сделать?

if (yourObject != null)
{
    ... do something meaningful with yourObject ...
}

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

Последние 15 лет я занимался обработкой исключений, начиная с первых шести версий Delphi, вплоть до (и включая) .NET 1.0-4.0. Это мощный инструмент, но он часто используется слишком часто. Я обнаружил, что в течение этого времени наиболее эффективный процесс обработки исключений - откладывание до if-then до try-catch.

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