通过反射,我正在调用一个可能导致异常的方法。我怎样才能将异常传递给我的调用者而没有包装反射围绕它? 我重新抛出InnerException,但这破坏了堆栈跟踪。 示例代码:

public void test1()
{
    // Throw an exception for testing purposes
    throw new ArgumentException("test1");
}

void test2()
{
    try
    {
        MethodInfo mi = typeof(Program).GetMethod("test1");
        mi.Invoke(this, null);
    }
    catch (TargetInvocationException tiex)
    {
        // Throw the new exception
        throw tiex.InnerException;
    }
}

当前回答

伙计们,你们真酷。我很快就会成为一名死灵法师。

    public void test1()
    {
        // Throw an exception for testing purposes
        throw new ArgumentException("test1");
    }

    void test2()
    {
            MethodInfo mi = typeof(Program).GetMethod("test1");
            ((Action)Delegate.CreateDelegate(typeof(Action), mi))();

    }

其他回答

首先:不要丢失TargetInvocationException——当你想调试东西时,它是很有价值的信息。 第二:将TIE包装为您自己的异常类型中的InnerException,并放置一个OriginalException属性,该属性链接到您需要的内容(并保持整个调用堆栈完整)。 第三:让TIE冒泡退出方法。

另一个使用异常序列化/反序列化的示例代码。 它不要求实际的异常类型是可序列化的。 此外,它只使用公共/受保护的方法。

    static void PreserveStackTrace(Exception e)
    {
        var ctx = new StreamingContext(StreamingContextStates.CrossAppDomain);
        var si = new SerializationInfo(typeof(Exception), new FormatterConverter());
        var ctor = typeof(Exception).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }, null);

        e.GetObjectData(si, ctx);
        ctor.Invoke(e, new object[] { si, ctx });
    }

伙计们,你们真酷。我很快就会成为一名死灵法师。

    public void test1()
    {
        // Throw an exception for testing purposes
        throw new ArgumentException("test1");
    }

    void test2()
    {
            MethodInfo mi = typeof(Program).GetMethod("test1");
            ((Action)Delegate.CreateDelegate(typeof(Action), mi))();

    }

在。net 4.5中现在有了ExceptionDispatchInfo类。

这可以让你捕获一个异常并重新抛出它而不改变堆栈跟踪:

using ExceptionDispatchInfo = 
    System.Runtime.ExceptionServices.ExceptionDispatchInfo;

try
{
    task.Wait();
}
catch(AggregateException ex)
{
    ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}

这适用于任何异常,而不仅仅是AggregateException。

它的引入是由于await c#语言特性,该特性从AggregateException实例中展开内部异常,以便使异步语言特性更像同步语言特性。

更多的反思……

catch (TargetInvocationException tiex)
{
    // Get the _remoteStackTraceString of the Exception class
    FieldInfo remoteStackTraceString = typeof(Exception)
        .GetField("_remoteStackTraceString",
            BindingFlags.Instance | BindingFlags.NonPublic); // MS.Net

    if (remoteStackTraceString == null)
        remoteStackTraceString = typeof(Exception)
        .GetField("remote_stack_trace",
            BindingFlags.Instance | BindingFlags.NonPublic); // Mono

    // Set the InnerException._remoteStackTraceString
    // to the current InnerException.StackTrace
    remoteStackTraceString.SetValue(tiex.InnerException,
        tiex.InnerException.StackTrace + Environment.NewLine);

    // Throw the new exception
    throw tiex.InnerException;
}

请记住,这可能会在任何时候中断,因为私有字段不是API的一部分。参见Mono bugzilla的进一步讨论。