Чем отличается throw от throw ex при перебросе исключения? Почему throw ex сбрасывает stack trace и усложняет поиск первопричины?
Что это: Оператор throw без операнда внутри catch перебрасывает текущее исключение с сохранением исходного stack trace. throw ex создаёт новое место возникновения исключения и перезаписывает StackTrace, скрывая реальную строку, где ошибка произошла впервые.
Почему важно: Это базовая тема диагностики: на собеседовании проверяют, умеет ли кандидат не ломать логирование и расследование инцидентов в production.
Под капотом: CLR хранит stack trace в поле _stackTraceString объекта Exception. throw в catch использует инструкцию rethrow, которая не сбрасывает контекст. throw ex фактически бросает тот же объект заново из текущего кадра, и Runtime обновляет точку возникновения.
Типичная ошибка: Разработчики пишут catch (Exception ex) { Logger.Log(ex); throw ex; } и теряют исходную строку кода в логах, тратя часы на поиск настоящего источника ошибки в верхнем слое обёртки.
try
{
throw new InvalidOperationException('root');
}
catch (Exception ex)
{
// throw ex; // ПЛОХО: stack trace начнётся здесь
throw; // ХОРОШО: сохраняет исходный stack trace
}