Перебор с повторным использованием
Недавно один пользователь задал такой вопрос:
У меня есть код, который обслуживает очередь рабочих элементов, ожидающих обработки несколькими рабочими потоками. В некоторых ситуациях, вследствие катастрофических ошибок, я завершаю обработку элементов путем генерации исключения. Могу ли я создать всего лишь один объект исключения? Существуют ли какие-то проблемы при генерации того же самого объекта исключения несколько раз в разных потоках?
Каждый, кто хотя бы один раз видел подобное во время анализа кода, знает ответ:
catch(Exception ex)
{
Logger.Log(ex);
throw ex;
}
Это классическая «уловка». Практически всегда нужно писать “throw;”, а не “throw ex;”, потому что исключения не являются полностью неизменяемыми ( immutable ) в . NET. Сведения о трассировке стека (stack trace) объекта исключения устанавливаются в месте генерации исключения, каждый раз при его возникновении, а не в точке его создания. Выражение “throw;” не «сбрасывает» трассировку стека, а “throw ex;” – сбрасывает.
Не используйте повторно один и тот же объект исключения. Каждый раз при генерации исключения сведения трассировки стека сбрасываются, а это означает, что любой код, расположенный выше по стеку, перехвативший исключение и записавший трассировочную информацию для последующего анализа, практически наверняка сохранит трассировочную информацию не того исключения. Создание исключения – операция дешевая, кроме того, в этом случае вы находитесь в критической ситуации, поэтому совершенно не важно, если приложение упадет на несколько микросекунд позднее. Уделите время созданию такого количества исключений, сколько вы собираетесь генерировать.