стек вызовов исключений усечено без повторного выброса

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

   at (my class).MyMethod() in C:\(my file path and line)

На самом деле существует, вероятно, 30 методов, ведущих к этому в стеке вызовов отладчика VS2010, которые проходят через полдюжины различных сборок. Кажется невозможным, чтобы все это было оптимизировано. Более того, этот код построен в режиме отладки , без оптимизации , для .NET 4. У меня даже есть (на основе http://msdn.microsoft.com/en-us/library/9dd8z24x .aspx ) .ini (включая файл с именем [app] .vshost. ini) в той же папке, содержащей:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

Кроме того, вызовы методов не находятся в конце методов, поэтому оптимизация хвостовой рекурсии кажется маловероятной.

Что касается того, как она вызывается: нет использования отражения в стек вызовов, никаких Invoke () или BeginInvoke () любого типа. Это всего лишь длинная цепочка вызовов от нажатия кнопки. Обработчик кликов - это около 10 вызовов вниз по стеку вызовов. Ниже у вас есть обычные WndProc, NativeWindow.Callback, собственные / управляемые переходы и цикл сообщений. В конечном итоге это происходит внутри вызова ShowDialog (), который запускается из сборки C # EXE.

Теперь я обнаружил, что могу создавать экземпляры класса StackTrace в моем обработчике catch, и если я передаю объект Exception, стек вызовов тоже короткий. Если вместо этого я просто вызываю new StackTrace () без аргументов, это дает полный стек вызовов.

Я использовал Reflector в попытке отладить внутреннюю часть генерируемого класса Exception и построение его стека вызовов, но мне не удалось установить точки останова в Exception или в StackTrace. Я мог бы установить их в Environment.GetStackTrace (), и этот метод (который вызывает Exception), похоже, не вызывается во время процесса построения и выброса, но я не знаю, действительно ли отладчик работает правильно. (Этот метод действительно запускается для некоторых других вещей, поэтому я не уверен, что с этим делать.)

Вот выдержка из метода:

private void MyMethod()
{
    ...               
    try
    {
        throw new ApplicationException("Test failure");
    }
    catch (Exception e)
    {
        StackTrace stackTrace1 = new StackTrace(e);
        StackTrace stackTrace2 = new StackTrace(e, false);
        StackTrace stackTrace3 = new StackTrace(e, true);
        StackTrace stackTrace4 = new StackTrace();
        string STs = stackTrace1.ToString() + "\n---\n"
            + stackTrace2.ToString() + "\n---\n"
            + stackTrace3.ToString() + "\n---\n"
            + stackTrace4.ToString();
        Log(EventSeverity.Debug, STs);
        ...
        }
    }

Это действительно довольно просто: выбросить исключение, поймать и зарегистрировать его .

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


Это слишком много, чтобы добавить его в качестве комментария к предоставленному ответу, но вот еще кое-что:

Я сейчас видите, что это поведение обсуждается на http://dotnetoughtts.wordpress.com/2007/10/27/where-did-my-exception-occur/ и что фактически это описано на http://msdn.microsoft. com / en-us / library / system.exception.stacktrace.aspx (хотя я думаю, что можно легко пропустить то, что они там говорят).

Так что я думаю, что мое «решение» будет немного хитом - или-пропустить. У нас есть центральный метод, который мы обычно вызываем для форматирования исключений. Внутри этого метода я создам новый StackTrace () как с объектом Exception, так и без него. Затем я буду искать метод, который находится внизу трассировки стека исключения, и отображать все, что находится под ним, в новом StackTrace (), указывая, что он был вызван этой серией вызовов.

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

16
задан Todd 14 March 2011 в 18:34
поделиться