Найти, где сгенерированное исключение было первоначально выдано с использованием отладчика Visual Studio C #? - PullRequest
7 голосов
/ 10 февраля 2012

Обычный совет при отбрасывании исключения - использовать оператор throw;, чтобы сохранить исходную трассировку стека. ( Пример )

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

namespace ExceptionTest
{
    class Program
    {
        static void ThrowException()
        {
            throw new System.Exception();  // The line that I WANT the debugger to show.
        }

        static void Main(string[] args)
        {
            try
            {
                ThrowException();
            }
            catch (System.Exception)
            {
                System.Console.WriteLine("An exception was thrown.");

                throw;  // The line that the debugger ACTUALLY shows.
            }
        }
    }
}

Как я могу использовать отладчик, чтобы найти исходный источник исключения?

Ответы [ 5 ]

9 голосов
/ 10 февраля 2012

Лучший вариант - попросить Visual Studio использовать исходное исключение, а не переходить к нему из трассировки стека. Для этого:

1) Нажмите на пункт меню «Отладка» 2) Нажмите «Исключения ...» 3) Выберите «Общепринятые языковые исключения» - «Брошенный»

При таком подходе вы можете получить больше, чем вы на самом деле хотели, если было выброшено много исключений. Вы можете отфильтровать, какие исключения он нарушает, расширив список деревьев.

См. Изображение:

enter image description here

7 голосов
/ 11 апреля 2012

Если вы используете Visual Studio 2010 Ultimate, используйте IntelliTrace .

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

(взято из ответа Криса Шмиха на похожий вопрос .)

1 голос
/ 17 июня 2014

Вы можете использовать атрибут DebuggerNonUserCode.

См. http://blogs.msdn.com/b/jmstall/archive/2007/02/12/making-catch-rethrow-more-debuggable.aspx

Пример становится таким:

namespace ExceptionTest
{
    class Program
    {
        static void ThrowException()
        {
            throw new System.Exception();  // The line that I WANT the debugger to show.
        }

        [DebuggerNonUserCode()]
        static void Main(string[] args)
        {
            try
            {
                ThrowException();
            }
            catch (System.Exception)
            {
                System.Console.WriteLine("An exception was thrown.");

                throw;  // The line that the debugger ACTUALLY shows.
            }
        }
    }
}
1 голос
/ 15 февраля 2012

Лучшее решение, которое я нашел, это записать Exception callstack в Debug.Console и затем позволить встроенному анализатору строк кода в Visual Studio обеспечить навигацию.

Я нашел это действительно полезным при работе с необработанными исключениями в AppDomain и WPF Dispatcher , поскольку Visual Studio всегда прерывается слишком поздно.

Основываясь на статье о Code Project , я изменил ее, чтобы она выводила на Консоль в виде единого блока текста, а не построчно, который был необходимо у меня есть запись в журнал и запись в Console .

Использование

public void ReportException(Exception exception)
{
    if (Debugger.IsAttached)
    {
        DebugHelper.PrintExceptionToConsole(exception);
        Debugger.Break();
    }

    // ...

}

Источник

public static class DebugHelper
{
    // Original idea taken from the CodeProject article 
    // http://www.codeproject.com/Articles/21400/Navigating-Exception-Backtraces-in-Visual-Studio

    private static readonly string StarSeparator = new String('*', 80);
    private static readonly string DashSeparator = new String('-', 80);
    private const string TabString = "   ";

    /// <summary>
    /// Prints the exception using a format recognized by the Visual Studio console parser.
    /// Allows for quick navigation of exception call stack.
    /// </summary>
    /// <param name="exception">The exception.</param>
    public static void PrintExceptionToConsole(Exception exception)
    {
        using (var indentedTextWriter = new IndentedTextWriter(Console.Out, TabString))
        {                
            var indentLevel = 0;
            while (exception != null)
            {
                indentedTextWriter.Indent = indentLevel;
                indentedTextWriter.Write(FormatExceptionForDebugLineParser(exception));
                exception = exception.InnerException;
                indentLevel++;
            }
        }
    }

    private static string FormatExceptionForDebugLineParser(Exception exception)
    {
        StringBuilder result = new StringBuilder();

        result.AppendLine(StarSeparator);
        result.AppendLineFormat("  {0}: \"{1}\"", exception.GetType().Name, exception.Message);
        result.AppendLine(DashSeparator);

        // Split lines into method info and filename / line number
        string[] lines = exception.StackTrace.Split(new string[] { " at " }, StringSplitOptions.RemoveEmptyEntries)
                                                .Select(x => x.Trim())
                                                .Where(x => !String.IsNullOrEmpty(x))
                                                .ToArray();

        foreach (var line in lines)
        {
            string[] parts = line.Split(new string[] { " in " }, StringSplitOptions.RemoveEmptyEntries);
            string methodInfo = parts[0];
            if (parts.Length == 2)
            {
                string[] subparts = parts[1].Split(new string[] { ":line " }, StringSplitOptions.RemoveEmptyEntries);
                result.AppendLineFormat("  {0}({1},1): {2}", subparts[0], Int32.Parse(subparts[1]), methodInfo);
            }
            else
                result.AppendLineFormat("  {0}", methodInfo);
        }

        result.AppendLine(StarSeparator);

        return result.ToString();
    }

}

Чтобы использовать вышеуказанное, как есть, вам также понадобится метод расширения, указанный ниже, и добавьте пространство имен System.CodeDom.Compiler для IndentedTextWriter.

Метод расширения

/// <summary>
/// Appends the string returned by processing a composite format string followed by the default line terminator.
/// </summary>
/// <param name="sb">The StringBuilder.</param>
/// <param name="format">The format.</param>
/// <param name="args">The args.</param>
public static void AppendLineFormat(this StringBuilder sb, string format, params object[] args)
{
    sb.AppendFormat(format, args);
    sb.AppendLine();
}
0 голосов
/ 10 февраля 2012

Между прочим, в vb.net можно использовать фильтры исключений в некоторых ситуациях, подобных этой, когда известно, что никто не заинтересован в обнаружении исключения - просто выясняет, что это произошло. Если бы код был написан на vb.net и использовал фильтр для захвата исключения (возможно, делая сам вывод в блоке 'finally'), то не было бы «лови и перебрасывай» - курсор переместится на источник исходного исключения (в качестве бонуса vs прервет поток программы до того, как произойдет какое-либо разматывание стека). Обратите внимание, что каждый раз может быть выбрано vs trap каждый раз, когда выбрасывается конкретное исключение, независимо от того, будет оно перехвачено или нет, но иногда интересуются только некоторые места, где выбрасывается исключение, а не все.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...