Перебор с повторным использованием

Недавно один пользователь задал такой вопрос:

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

Каждый, кто хотя бы один раз видел подобное во время анализа кода, знает ответ:

catch(Exception ex)
{
   Logger.Log(ex);
   throw ex;
}

Это классическая «уловка». Практически всегда нужно писать “throw;”, а не “throw ex;”, потому что исключения не являются полностью неизменяемыми ( immutable ) в . NET. Сведения о трассировке стека (stack trace) объекта исключения устанавливаются в месте генерации исключения, каждый раз при его возникновении, а не в точке его создания. Выражение “throw;” не «сбрасывает» трассировку стека, а “throw ex;” – сбрасывает.

Не используйте повторно один и тот же объект исключения. Каждый раз при генерации исключения сведения трассировки стека сбрасываются, а это означает, что любой код, расположенный выше по стеку, перехвативший исключение и записавший трассировочную информацию для последующего анализа, практически наверняка сохранит трассировочную информацию не того исключения. Создание исключения – операция дешевая, кроме того, в этом случае вы находитесь в критической ситуации, поэтому совершенно не важно, если приложение упадет на несколько микросекунд позднее. Уделите время созданию такого количества исключений, сколько вы собираетесь генерировать.

Оригинал статьи