2009-09-01 5 views
3

Я подтвердил это же поведение в VS2005, поэтому я ошибся называть его ошибкой .NET (1.1).Отображение трассировки стека исключений, которые были повторно выбраны, а не трассировки стека из точки бросания

Я оставляю исходный вопрос ниже, но мой пересмотренный вопрос таков: как мне получить Visual Studio, чтобы дать мне трассировку стека исключения, которое я поймал, и повторно выбрал в окне окна вызова , а не только отображать стек вызовов из точки оператора throw?

Ситуация такова, что я решаю во время выполнения является ли глобальный обработчик исключений или выключен - если он выключен, я хочу VS, чтобы поймать исключение, так что я могу пройти через стек вызовов, чтобы выяснить, что пошло неправильно.

Ранее глобальный обработчик исключений либо был скомпилирован в программу, либо нет. Но ситуация изменилась, и теперь мы должны решить, во время выполнения - это выглядит, как я, возможно, придется вернуться к макро способ сделать это, но без макросов:

if (allow_bubble_up) 
{ 
    Foo(); 
} 
else 
{ 
    try 
    { 
     Foo(); 
    } 
    catch (Exception e) 
    { 
     GlobalExceptionHandler(e); 
    } 
} 

Но этот подход чувствует чрезвычайно против СУХОЙ, мне.


Видимо есть ошибка в .NET 1.1, где, если у вас есть пустой throw заявление повторно бросить пойманной исключение, трассировки стека начинается от того, где что throw произошло, вместо трассировки стека из все исключение было переброшено - по крайней мере, я видел, что это вызвало ошибку в нескольких блогах, но я не смог получить гораздо больше информации об этом.

Чтобы быть более конкретным, свойство StackTrace$exception в QuickWatch показывает правильные данные, но окно вызова стека в VS показывает только стек вызовов до уровня оператора throw.

В этом примере кода я могу видеть только 1-уровень-глубокий трассировку стека Main, хотя я должен увидеть трассировки стека пары вызовов Foo.

static public void Foo(int i) 
{ 
    if (i > 4) 
    { 
     throw new ArgumentOutOfRangeException(); 
    } 
    Foo(i + 1); 
} 

static void Main(string[] args) 
{ 
    bool allow_bubble_up = true; 
    try 
    { 
     Foo(0); 
    } 
    catch (Exception e) 
    { 
     if (allow_bubble_up) 
     { 
      // stack trace just shows Main 
      throw; 

      // also just shows Main 
      //throw new Exception("asdf", e); 

      // STILL just shows Main 
      //throw e; 
     } 
     else 
     { 
      System.Console.WriteLine(e); 
     } 
    } 
} 

Fabrice Marguerie's blog показывает, как работать вокруг повторно брошен стек следов какого-то для .NET 2.0+, и в нижней части он говорит, чтобы проверить блог Криса Тейлора о том, как сделать это в .NET 1.1. Мне пришлось искать немного до find it on archive.org. I думаю Я реализовал его правильно, но у меня все еще есть трассировка стека только на главном - его объяснение было не очень ясным, и я бы предпочел не связываться с базой кода (обернуть существующий набор функций другим способом) не более, чем необходимо.

Я вижу правильную трассировку стека в свойствах пойманного и повторно поднятого исключения, но трассируемая трассировка стека, которую показывает VS, бесполезна, поскольку она отслеживает только из инструкции throw. Если я никогда не поймаю и не переброшу исключение, я получаю полную и правильную трассировку стека, do.

Как получить правильную трассировку стека, отображаемую в VS? Я надеюсь, что есть какой-то простой способ обхода проблемы, и что я только что искал неправильные условия.

И, к сожалению, для этого должен быть VS2003 + C#.

Если бы не было иначе ясно, вот скриншот (вам, вероятно, нужно щелкнуть правой кнопкой мыши и просмотра изображений):

alt text http://img257.imageshack.us/img257/1124/40727627.png

+1

Я помню, что это очень расстраивало 1.1. Никогда не искал решения в то время, но ты не сумасшедший. Я знаю, что Вы имеете ввиду! Но не так сильно разочаровывающе, как я предполагаю, что все еще использовать 1.1 может быть! –

+0

Это выглядит правильно, так как Main является вызывающим фактором Foo, который в итоге выбрал исключение. – user7116

+0

@Mark Rushakoff: Я выделил точку окна «Стек вызовов», которая была самой большой точкой смятения. – user7116

ответ

3

Оказалось, что если вы знаете правильные условия для поиска, там является Ответ на проблему, которую я пытался решить. В MSIL это называется фильтрацией исключений и it is available in VS2003.

В Visual Basic.NET существует конструкция, называемая «catch-when», которая будет выполнять захват только при прохождении данного предиката. This MSDN blog имеет отличный пример того, как catch-when работает в VB.NET по сравнению с результатами (например, моими) уловов C#.

Наконец, MSDN имеет инструмент под названием Exception Filter Inject, который может использоваться для «предоставления поддержки фильтра исключений для языков (таких как C#), которые не имеют поддержки фильтра исключений» - уловка заключается в том, что он выполняется на существующей сборке, поэтому он вводит неудобную стадию в процессе сборки, если вы в конечном итоге ее используете.


Прежде чем я нашел Exception фильтр Inject, я в конечном итоге реализации короткую функцию, которая приняла «функциональный» делегат и «поймать» делегата, и просто назвать функциональным, если исключения были допущены пузыриться, в противном случае называемый функционалом в try-catch, вызывающий делегат catch в исключенном исключении.

Что я хотел делать, чтобы как-то привести меня найти фильтрации исключений, должна была быть в состоянии установить тип исключения, чтобы поймать во время выполнения - если исключения должны были пузыриться, я бы попытался поймать исключение подкласса, которое никогда не будет вызываться, иначе я бы просто заметил базовое исключение. Я действительно не уверен, что это было бы возможно в .NET 1.1 или нет, поскольку это в основном потребовало бы общего - но, возможно, это было возможно с Reflection, я просто так и не получил этого в моих исследованиях.

3

Вы могли бы бросить новое исключение, помещая исключение е как внутреннее исключение. Затем прочитайте stacktrace внутреннего исключения.

+1

Я могу прочитать трассировку стека как строку просто отлично, но когда мне нужно перемещаться по стеку вызовов, чтобы выяснить, что пошло не так, у меня нет выбора, кроме как вручную найти файл и строку каждого элемента в стеке вызовов. –

+0

Итак, чего не хватает в Visual Studio, которая должна быть там? Наверное, это мой вопрос. – user7116

4

Visual Studio покажет стопку вызовов того места, где находится останавливается.

В случае ошибки исключено исключение, оно остановится там, где будет выбрано это исключение. т. е. ваш «бросок». Но если ваш код обрабатывает исключение, Visual Studio предполагает, что вы знаете, что делаете, и игнорирует исключение. Это приведет к появлению исключения только в том случае, если оно повторно выбрано в Main(), потому что вы не обрабатываете его в своей программе.

Если вы хотите, чтобы поймать оригинальное исключение в Visual Studio, у вас есть два варианта:

  • не поймать исключение в коде. Visual Studio по умолчанию останавливается только на необработанных исключений. Это, конечно, означает, что ваша программа не будет обрабатывать исключения во время выполнения, поэтому это не очень полезный подход!

  • используйте ваш код, чтобы поймать и повторно выбросить исключение (как вы это делаете), но сконфигурируйте Visual Studio, чтобы остановить, когда первое исключение выбрано первым. Перейдите в раздел «Отладка»> «Исключения» и отметьте поле исключений «common language runtime» (для остановки для любого исключения) или просмотрите поддерево, чтобы включить исключение catch для определенных исключений (подсказка: если вы знаете имя исключения, нажмите кнопку «Найти ...» и введите часть имени, например «FileNotFound», чтобы быстро найти исключение). Это заставит VS остановиться во внутреннем исключении и только перейти к вашему catch {}, если вы решите продолжить выполнение после изучения деталей исключения.

+0

это ответ. властный. просто чисто мастерски. – djmc

1

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

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

Помимо включения «break on first exception», я не вижу, как это будет работать, и я ничего не знаю о VS2003 или VS2005, которые помогут в этом. (Возможно, новые функции отладки/воспроизведения в VS2010)

+0

+1, потребовалось некоторое время, чтобы понять, что это окно вызова стека. – user7116

+0

Было замешательство (в основном/все с моей стороны) о трассировке стека повторного исключения. Свойство 'StackTrace' исключения является правильным, но я хотел бы сделать VS break и позволить мне перемещаться по стеке вызовов, как будто я вообще не заметил исключения. Я понимаю вашу точку зрения о том, что «Foo» закончил, а временные переменные перестали существовать. Вероятно, мне придется поставить try-catch в отдельную ветку оператора if, как я упоминал в редакции в начале вопроса. Просто держите его открытым, если кто-то знает другой подход, сейчас. –

1

Что вы описываете, это ожидаемое поведение окна «Стек вызовов». Когда Visual Studio ломается на линии throw из-за исключения UnhandledException, правильно показать шоу стека вызовов, начиная с строки throw.

Это сводится к тому, что окно стека окон Visual Studio не знает о трассировке стека, содержащейся в вашем исключении.

+0

+1, я ошибочно полагал, что пустой «бросок» будет действовать так, как будто я никогда не поймал исключение вообще. Я оставляю вопрос открытым, чтобы узнать, знает ли кто-нибудь * способ обмануть VS в этом режиме, иначе я, вероятно, буду принимать ваш ответ. –

Смежные вопросы