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так что вы должны сказать отладчику прерывать при исключениях первого шанса:

  1. Отладка "Исключения... (Ctrl+Alt+E)
  2. Отметьте "Брошенный" для типов исключений, о которых вы заботитесь (в данном случае, Commange Language Runtime Exceptions)
  3. Нажмите ОК
  4. Начать отладку

В этом случае отладчик сразу сломается, когда 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] а так и тд...)

Другие вопросы по тегам