[英]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. 我发现它在处理AppDomain和WPF 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.