что может привести к сбросу стоп-кадра (я использую «throw», а не «throw ex»)

Я всегда считал, что разница между «throw» и «throw ex» заключалась в том, что бросок в одиночку не возвращал значение stacktrace исключения.

К сожалению, это не то поведение, которое я испытываю; вот простой пример, воспроизводящий мою проблему:

using System; using System.Text; namespace testthrow2 { class Program { static void Main(string[] args) { try { try { throw new Exception("line 14"); } catch (Exception) { throw; // line 18 } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.ReadLine(); } } } 

Я ожидаю, что этот код напечатает стоп-стол, начиная с строки 14; однако столбец начинается с строки 18. Конечно, это не имеет большого значения в выборке, но в моем реальном приложении, потеря исходной информации об ошибке довольно болезненна.

Мне что-то не хватает? Есть ли другой способ достичь того, что я хочу (т. Е. Повторно бросать исключение, не теряя информацию о стеке?)

Я использую .net 3.5

Вы должны прочитать эту статью:

  • Исключение исключений и сохранение полной стека стека вызовов

Короче говоря, throw обычно сохраняет трассировку стека исходного исключенного исключения, но только если исключение не произошло в текущем фрейме стека (т.е. метод).

Существует метод PreserveStackTrace (показан в этой статье в блоге), который вы используете, который сохраняет исходную трассировку стека следующим образом:

 try { } catch (Exception ex) { PreserveStackTrace(ex); throw; } 

Но мое обычное решение состоит в том, чтобы просто не перехватывать и повторять исключения вроде этого (если это абсолютно необходимо), или просто всегда бросать новые исключения, используя свойство InnerException для распространения исходного исключения:

 try { } catch (Exception ex) { throw new Exception("Error doing foo", ex); } 

Проблема в том, что Windows сбрасывает исходную точку стека. CLR ведет себя как ожидалось – это просто ограничение поддержки обработки исключений операционной системы хоста. Проблема в том, что на вызов метода может быть только один стек.

Вы могли бы извлечь ваши процедуры обработки исключений в отдельный «вспомогательный» метод, который будет работать с ограничениями, наложенными Windows SEH, но я не думаю, что это обязательно хорошая идея.

Правильный способ повторного исключения исключений без потери информации о стеке – это выбросить новое исключение и включить исходное исключенное исключение в качестве внутреннего исключения.

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

Нормальный ретрон сохраняет все в трассировке стека за исключением того, что если данный метод находится в трассировке стека, номер строки будет перезаписан. Это раздражает поведение. В C #, если нужно что-то сделать в исключительном случае, но все равно, что такое исключение, можно использовать шаблон:

   Boolean ok = False;
   пытаться
   {
     сделай что-нибудь();
     ok = True;
   }
   в конце концов
   {
     if (! ok) // Произошло исключение!
       handle_exception ();
   }

Есть ряд, где эта схема очень полезна; наиболее распространенной будет функция, которая должна возвращать новый IDisposable. Если функция не вернется, одноразовый объект должен быть очищен. Обратите внимание, что любые операторы «return» в вышеуказанном блоке «try» должны установить ok в true .

В vb.net можно использовать шаблон, который функционально немного приятнее, хотя одно место в коде немного нехорошо, с шаблоном:

   Dim PendingException As Exception = Nothing;
   Пытаться
     Сделай что-нибудь
     PendingException = Nothing 'См. Примечание
   Catch Ex As Exception Когда CopyFirstParameterToSecondAndReturnFalse (Ex, PendingException)
     Throw 'никогда не выполнится, так как выше вернет false
   в заключение
     Если PendingException IsNot Nothing Then
       Исключение Handle
     EndIf
   Конец Попробуйте

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

Одна интересная заметка с приведенным выше кодом: возможно, что исключение достигло «Catch When», но все же для завершения инструкции Try. В самом деле непонятно, что должно произойти в этом случае, но ясно одно, что оператор «Окончание» не должен действовать так, как если бы исключение ожидало. Очистка PendingException сделает так, что если исключение исчезнет, ​​код будет вести себя так, как будто этого не произошло. Альтернативой было бы обернуть и перебросить исключение, которое, как известно, произошло, поскольку эта ситуация почти наверняка указывает на что-то неправильное с внутренним кодом обработки исключений.

  • Как можно захватить трассировку стека в C?
  • В чем разница между parent.frame () и parent.env () в R; как они отличаются при вызове по ссылке?
  • где найти значение XSS по умолчанию для Sun / Oracle JVM?
  • GetEntryAssembly для веб-приложений
  • Почему термины «автоматический» и «динамический» предпочтительнее терминов «стек» и «куча» в управлении памятью C ++?
  • Почему максимальная глубина рекурсии я могу достичь недетерминированной?
  • Почему Mac ABI требует 16-байтного выравнивания стека для x86-32?
  • Почему стеки обычно растут вниз?
  • Жизненный цикл classа приложений Android
  • Создание объекта в стеке / куче?
  • Есть ли стековая или безвыходная реализация C ++?
  • Давайте будем гением компьютера.