将StackTrace附加到exception而不在C#/ .NET中抛出

我有一个使用返回值处理错误的组件,而不是标准的exception处理。 除了错误代码之外,它还返回错误发生位置的堆栈跟踪。 我用来调用组件的包装器将解释返回代码并抛出exception。

我想让包装器抛出一个exception,其中包含从组件中捕获的堆栈跟踪信息。 我希望看起来好像exception是从错误的原始站点抛出的,即使它被抛到其他地方。 更具体地说,id就像visual studio测试运行器显示的堆栈跟踪,以反映正确的位置

有没有办法做到这一点? 如果我可以避免访问私人成员的低级reflection技巧,那也很好,但我会采取我能得到的。

编辑1:我不关心如何捕获堆栈跟踪,我关心的是将已经捕获的堆栈跟踪附加到exception

编辑2:

我尝试重写StackTrace属性,但是visual studio正在从其他地方提取堆栈跟踪数据,并且似乎完全忽略了被覆盖的属性

CustomException GenerateExcpetion() { return new CustomException(); } void ThrowException(Exception ex) { Trace.WriteLine("Displaying Exception"); Trace.WriteLine(ex.ToString()); var edi = ExceptionDispatchInfo.Capture(ex); edi.Throw(); } [TestMethod] public void Test006() { var ex = GenerateExcpetion(); ThrowException(ex); } public class CustomException : Exception { string _stackTrace; public CustomException() { _stackTrace = Environment.StackTrace; } public override string StackTrace { get { return base.StackTrace; } } } 

Excpetion.ToString()方法从私有属性中提取堆栈跟踪数据,因此来自覆盖的堆栈跟踪不会显示。

CustomException:抛出了类型’CustomException’的exception。

ExceptionDispatchInfo也从私有属性中查找堆栈跟踪数据,因此它无法找到任何该数据,并且当您抛出此自定义exception时,新的堆栈跟踪将附加到exception,其位置为抛出。 如果直接使用throw,则私有堆栈信息将设置为发生抛出的位置。

只需创建自己的Exception类型并覆盖StackTrace属性:

 class MyException : Exception { private string oldStackTrace; public MyException(string message, string stackTrace) : base(message) { this.oldStackTrace = stackTrace; } public override string StackTrace { get { return this.oldStackTrace; } } } 

您可以使用: Environment.StackTrace在组件中出现错误时捕获堆栈跟踪,然后将其与其他错误信息或重新抛出一起返回。

您可以手动构建堆栈帧以创建完整跟踪: StackFrame

MSDN: StackTrace

没有优雅可用,这是我基于reflection的方法。

 public static class ExceptionUtilities { private static readonly FieldInfo STACK_TRACE_STRING_FI = typeof(Exception).GetField("_stackTraceString", BindingFlags.NonPublic | BindingFlags.Instance); private static readonly Type TRACE_FORMAT_TI = Type.GetType("System.Diagnostics.StackTrace").GetNestedType("TraceFormat", BindingFlags.NonPublic); private static readonly MethodInfo TRACE_TO_STRING_MI = typeof(StackTrace).GetMethod("ToString", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { TRACE_FORMAT_TI }, null); public static Exception SetStackTrace(this Exception target, StackTrace stack) { var getStackTraceString = TRACE_TO_STRING_MI.Invoke(stack, new object[] { Enum.GetValues(TRACE_FORMAT_TI).GetValue(0) }); STACK_TRACE_STRING_FI.SetValue(target, getStackTraceString); return target; } } 

将格式化的StackTrace字符串写入_stackTraceString属性似乎足以欺骗visual studio test runner和Exception.ToString()方法,使其相信堆栈是由throw生成的(实际上没有抛出任何东西)。

请参阅下面的用法:

  StackTrace GetDeeperStackTrace(int depth) { if (depth > 0) { return GetDeeperStackTrace(depth - 1); } else { return new StackTrace(0, true); } } [TestMethod] public void Test007() { Exception needStackTrace = new Exception("Some exception"); var st = GetDeeperStackTrace(3); needStackTrace.SetStackTrace(st); Trace.Write(needStackTrace.ToString()); throw new Exception("Nested has custom stack trace", needStackTrace); }