C# перебрасывает исключение: как получить стек исключений в IDE?
Ранее здесь обсуждался вопрос о правильном способе отбрасывания исключения. Вместо этого этот вопрос о том, как получить полезное поведение от Visual Studio при использовании rethrow.
Рассмотрим этот код:
static void foo() {
throw new Exception("boo!");
}
static void Main(string[] args) {
try {
foo();
} catch (Exception x) {
// do some stuff
throw;
}
}
Возникающее исключение имеет правильную трассировку стека, показывая foo() в качестве источника исключения. Однако окно GUI Call Stack показывает только Main, тогда как я ожидал, что оно покажет стек вызовов исключения, вплоть до foo.
Когда нет переброса, я могу использовать GUI для очень быстрой навигации по стеку вызовов, чтобы увидеть, какой вызов вызвал исключение и как мы туда попали.
С повторным броском я бы хотел сделать то же самое. Вместо этого стек вызовов, который показывает GUI, бесполезен для меня. Я должен скопировать детали исключения в буфер обмена, вставить его в Блокнот, а затем вручную перейти к любой функции стека вызовов, которая меня интересует.
Кстати, я получаю такое же поведение, если я добавляю [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
или если я изменю улов на просто catch (Exception)
,
У меня такой вопрос: учитывая, что код, который я использую, использует rethrow, может кто-нибудь предложить удобный способ навигации по стеку вызовов, связанному с исключением? Я использую Visual Studio 2010.
4 ответа
Отладчик ломается на throw
в Main
потому что это исключение не обработано. По умолчанию отладчик будет работать только на необработанные исключения. Как только вы остановились на Main
стек вызовов для исходного исключения из foo
присутствует в исключении, но весь другой контекст был потерян (например, локальные данные, состояние стека / памяти).
Похоже, вы хотите, чтобы отладчик сломался на throw
в foo
так что вы должны сказать отладчику прерывать при исключениях первого шанса:
- Отладка "Исключения... (Ctrl+Alt+E)
- Отметьте "Брошенный" для типов исключений, о которых вы заботитесь (в данном случае, Commange Language Runtime Exceptions)
- Нажмите ОК
- Начать отладку
В этом случае отладчик сразу сломается, когда foo
бросает исключение. Теперь вы можете проверить стек, локальные объекты и т. Д. В контексте исходного исключения. Если вы продолжите выполнение (F5), отладчик снова прекратит работу при повторной передаче в Main
,
Используя другой подход, если вы используете VS2010 Ultimate, вы также можете использовать IntelliTrace для "отладки назад", чтобы увидеть параметры, потоки и переменные во время исключения. См. Эту статью MSDN для деталей. (Полное раскрытие: я работаю в команде, тесно связанной с IntelliTrace).
Если вы используете ReSharper, вы можете скопировать трассировку стека исключений в буфер обмена, а затем выберите в меню: ReSharper> Инструменты> Просмотр трассировки стека (Ctrl + E, T). Он покажет трассировку стека с кликабельными местоположениями, так что вы сможете быстро перемещаться.
http://www.jetbrains.com/resharper/webhelp/images/Reference__Windows__Stack_Trace_Explorer.png
Эта функция также очень полезна при копании журналов пользователей (если в журнале регистрируются трассировки исключений).
Не то, чтобы вам нужно было перебрасывать, но вот сообщение в блоге о том, как сохранить трассировку стека, по сути это сводится к следующему:
private static void PreserveStackTrace(Exception exception)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
}
...
catch (Exception ex)
{
// do something
// ...
PreserveStackTrace(ex);
throw;
}
Майк Сталл дал отличное и простое решение вашей проблемы:
Отметьте методы, где вы перебрасываете исключение, с помощью атрибута [DebuggerNonUserCode]
IDE будет считать, что это не ваш код, и не сломает отладчик в таком месте, а вместо этого будет искать в стеке следующий шаг, показывая следующее повторное генерирование или начальное место исключения.
(если следующее повторение также раздражает, отметьте его как [DebuggerNonUserCode]
а так и тд...)