简体   繁体   English

查找最初使用Visual Studio C#debugger抛出rethrown异常的位置?

[英]Find where rethrown exception was originally thrown using Visual Studio C# debugger?

The usual advice when rethrowing an exception is to use a throw; 重新抛出异常时通常的建议是使用throw; statement so the original stack trace is preserved. 声明,以便保留原始堆栈跟踪。 ( Example ) 例子

However, when I try this simple example, the Visual Studio debugger does not show the original stack trace. 但是,当我尝试这个简单的示例时,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.
            }
        }
    }
}

How can I use the debugger to find the original source of the exception? 如何使用调试器查找异常的原始来源?

Your best option is to ask Visual Studio to break on the original exception rather than navigate back to it from the stack trace. 您最好的选择是让Visual Studio打破原始异常,而不是从堆栈跟踪导航回来。 To do this: 去做这个:

1) Click on the 'Debug' menu item 2) Click 'Exceptions...' 3) Select 'Common Language Runtime Exceptions' - 'Thrown' 1)单击“Debug”菜单项2)单击“Exceptions ...”3)选择“Common Language Runtime Exceptions” - “Thrown”

With this approach you may get more than you really wanted if there are many exceptions being thrown. 使用这种方法,如果抛出许多异常,您可能会得到比您真正想要的更多。 You can filter which exceptions it breaks on by expanding the tree list. 您可以通过展开树列表来过滤它中断的异常。

See image: 见图:

在此输入图像描述

If you're running Visual Studio 2010 Ultimate, use IntelliTrace . 如果您正在运行Visual Studio 2010 Ultimate,请使用IntelliTrace

It keeps a record of all exceptions thrown and allows you to "debug back in time" to see parameters, threads, and variables at the time of each throw. 它记录所有抛出的异常,并允许您“及时调试”以查看每次抛出时的参数,线程和变量。

(Taken from Chris Schmich's answer to a similar question .) (摘自Chris Schmich对类似问题的回答 。)

You can use the DebuggerNonUserCode Attribute. 您可以使用DebuggerNonUserCode属性。

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

The example becomes like this: 这个例子变成这样:

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.
            }
        }
    }
}

The best solution that I've found is write the Exception callstack to the Debug.Console and then let the built-in code line parser in Visual Studio to provide the navigation. 我发现的最佳解决方案是将Exception callstack写入Debug.Console ,然后让Visual Studio中的内置代码行解析器提供导航。

I found it really useful when dealing with unhandled exceptions on the AppDomain and WPF Dispatcher as Visual Studio always breaks too late. 我发现它在处理AppDomainWPF Dispatcher上的未处理异常时非常有用,因为Visual Studio总是打破得太晚。

Based from an article on Code Project , I have modified it that it outputs to the Console as a single block of text - rather than line-by-line - which was necessary I have logging also writing to the Console . 根据关于代码项目的文章,我修改了它作为单个文本块输出到控制台 - 而不是逐行 - 这是我必须记录也写入控制台的必要条件。

Usage 用法

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

    // ...

}

Source 资源

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();
    }

}

To use the above, as is, you will also need the Extension Method below and add the System.CodeDom.Compiler namespace for IndentedTextWriter . 要使用上面的内容,您还需要下面的扩展方法,并为IndentedTextWriter添加System.CodeDom.Compiler命名空间。

Extension Method 扩展方法

/// <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();
}

Incidentally, in vb.net, one can use exception filters in some situations like this where one knows one isn't really interested in catching an exception--just finding out that it happened. 顺便说一下,在vb.net中,可以在某些情况下使用异常过滤器,其中一个人知道一个人对捕获异常并不感兴趣 - 只是发现它发生了。 If the code were written in vb.net and used a filter to capture the exception (probably doing the output itself within the 'finally' block) there wouldn't be a "catch and rethrow"--the cursor would jump to the source of the original exception (as a bonus, vs would interrupt the program flow before any stack unwinding took place). 如果代码是在vb.net中编写的并且使用过滤器来捕获异常(可能在'finally'块中执行输出)那么就不会有“catch和rethrow” - 光标会跳转到源代码原始异常(作为奖励,vs会在任何堆栈展开之前中断程序流程)。 Note that one can opt to have vs trap every time a particular exception is thrown, whether or not it will be caught, but sometimes one is only interested in some of the places an exception is thrown, rather than all of them. 请注意,每次抛出特定异常时都可以选择使用vs trap,无论是否会被捕获,但有时候只会抛出一些抛出异常的地方而不是所有异常。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当我的代码在调试器中引发异常时,为什么Visual Studio 2010不向我显示弹出窗口以及引发异常的位置? - Why doesn't Visual Studio 2010 show me a popup and the location where an exception is thrown when my code throws an exception in the debugger? 用于C#的Visual Studio调试器的乘法问题 - Multiplication issue with Visual Studio debugger for C# 抛出异常:mscorlib.dll,Visual Studio C# 中的“System.IO.FileNotFoundException” - Exception thrown: 'System.IO.FileNotFoundException' in mscorlib.dll, Visual studio C# 在 Visual Studio 中,所有异常设置均未选中,但仍会引发一些异常并停止调试 (C#) - In Visual Studio, all exception settings are unchecked still some exceptions get thrown and debugging stops (C#) 如果使用Visual Studio在Xamarin Forms C#中从远程URL读取字符串,则抛出异常 - An exception is thrown if read string from remote url in Xamarin Forms C# with Visual Studio 在哪里可以找到 SaveFileDialog 的选定文件路径(C#,Visual Studio) - Where to find selected filepath of SaveFileDialog (C#, Visual Studio) 如何在C#中发生处理异常时停止Visual Studio调试器 - How to make the Visual Studio debugger stop when a handled exception occurs in C# 启动时的 Visual Studio 调试器异常 - Visual Studio Debugger exception on launch Visual Studio代码(使用C#):放入调试器点然后显示“没有为此文档加载符号” - Visual Studio code(using C#): While putting debugger point then showing me “No Symbol loaded for this document” 在C#中的Visual Studio调试器中查看数组的子部分 - View a subsection of an array in visual studio debugger in C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM