Ответ
Ключевое отличие — в сохранении оригинальной трассировки стека (stack trace), что критично для отладки.
throw;— повторно выбрасывает перехваченное исключение, сохраняя полный стек вызовов.throw ex;— выбрасывает то же исключение заново, но сбрасывает точку возникновения на текущую строку, обрезая стек вызовов.
Пример, демонстрирующий проблему:
void InnerMethod() {
throw new InvalidOperationException("Ошибка на низком уровне");
}
void OuterMethod() {
try {
InnerMethod();
}
catch (Exception ex) {
// ПЛОХО: стек будет указывать на эту строку, а не на InnerMethod
// throw ex;
// ХОРОШО: стек сохранит путь: OuterMethod -> InnerMethod
throw;
}
}
Когда что использовать:
- Всегда используйте
throw;при повторной генерации того же исключения в блокеcatch. Это стандартная практика. throw ex;практически никогда не нужен. Его единственное гипотетическое применение — намеренное сокрытие внутренней структуры кода (security through obscurity), что является антипаттерном.- Если нужно создать новое исключение с дополнительным контекстом, оберните оригинальное:
catch (Exception ex) { throw new ApplicationException("Не удалось обработать запрос", ex); // ex становится InnerException }