将StackTrace附加到异常,而无需抛出C#/ .NET [英] Attach StackTrace To Exception Without Throwing in C# / .NET

查看:166
本文介绍了将StackTrace附加到异常,而无需抛出C#/ .NET的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我希望包装程序抛出一个异常,该异常包括从组件中捕获的堆栈跟踪信息。我希望它看起来好像是从错误的原始位置抛出了异常,即使它是在其他地方抛出的也是如此。 更具体地说,id类似于Visual Studio测试运行器显示的堆栈跟踪,以反映正确的位置



有什么方法可以做到这一点?如果我可以避免访问私有成员的低级反射技巧,那也很好,但我会尽我所能。



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



编辑2:



我尝试覆盖StackTrace属性,但是Visual Studio正在从其他位置提取堆栈跟踪数据,并且似乎忽略了完全重写属性

  CustomException GenerateExcpetion()
{
返回新的CustomException();
}

void ThrowException(Exception ex)
{
Trace.WriteLine( Displaying Exception);
Trace.WriteLine(ex.ToString());
var edi = ExceptionDispatchInfo.Capture(ex);
edi.Throw();
}

[TestMethod]
公共无效Test006()
{
var ex = GenerateExcpetion();
ThrowException(ex);
}

公共类CustomException:异常
{
string _stackTrace;
public CustomException()
{
_stackTrace = Environment.StackTrace;
}

公共替代字符串StackTrace
{
get
{
return base.StackTrace;
}
}
}

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



CustomException:抛出了'CustomException'类型的异常。 / p>

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

解决方案

很好,没有可用的方法,这是我基于反射的方法。

 公共静态类ExceptionUtilities 
{
private static readonly FieldInfo STACK_TRACE_STRING_FI = typeof(Exception).GetField( _ stackTraceString,BindingFlags.NonPublic | BindingFlags.Instance);
私有静态只读Type TRACE_FORMAT_TI = Type.GetType( System.Diagnostics.StackTrace)。GetNestedType( TraceFormat,BindingFlags.NonPublic);
私有静态只读MethodInfo TRACE_TO_STRING_MI = typeof(StackTrace).GetMethod( ToString,BindingFlags.NonPublic | BindingFlags.Instance,null,新[] {TRACE_FORMAT_TI},null);

公共静态异常SetStackTrace(此异常目标,StackTrace堆栈)
{
var getStackTraceString = TRACE_TO_STRING_MI.Invoke(堆栈,新对象[] {Enum.GetValues(TRACE_FORMAT_TI)。 GetValue(0)});
STACK_TRACE_STRING_FI.SetValue(target,getStackTraceString);
美元的回报目标;
}
}

将格式化的StackTrace字符串写入_stackTraceString属性似乎足以愚弄Visual Studio测试运行程序和Exception.ToString()方法,以认为堆栈是由抛出生成的(实际上没有抛出任何东西)。



请参见下文用法:

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

抛出new Exception(嵌套具有自定义堆栈跟踪,needStackTrace);
}


I have a component which handles errors using return values as opposed to standard exception handling. In addition to the error code, it also returns a stack trace of where the error has occurred. A wrapper i use to invoke the component will interpret return codes and throw an exception.

I'd like to have the wrapper throw an exception that includes the captured stack trace information from the component. I'd like it to appear as if the exception had been thrown from the original site of the error even though it was thrown elsewhere. More specifically, id like the stack trace displayed by the visual studio test runner to reflect the proper location

Is there any way to do this? It would also be nice if I could avoid low-level reflection tricks accessing private members but i will take what i can get.

EDIT 1: I'm not concerned with how to capture a stack trace, i'm concerned with attaching a stack trace that's already been captured, to an Exception

EDIT 2:

I tried overriding the StackTrace property, but visual studio is pulling the stack trace data from somewhere else, and seems to ignore the overridden property completely

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

The Excpetion.ToString() method pulls stack trace data from a private property, and so the stack trace coming from the override doesnt get shown.

CustomException: Exception of type 'CustomException' was thrown.

The ExceptionDispatchInfo looks for the stack trace data from a private property as well, and so it can't find any of that data, and when you throw this custom exception a new stack trace is attached to the exception with the location that it is being thrown from. If you use throw directly, the private stack information is set to the place where the throw happened.

解决方案

Well with nothing elegant available, here is my reflection based approach.

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

Writing a formatted StackTrace string to the _stackTraceString property seems to be enough to fool visual studio test runner and the Exception.ToString() methods into believing the stack was generated by a throw (without actually throwing anything).

See below for usage:

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

这篇关于将StackTrace附加到异常,而无需抛出C#/ .NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆