使用ContructorInfo.Invoke时Stacktrace混淆

时间:2014-03-25 11:57:32

标签: c# exception

大家都很聪明,

在C#中处理.NET Reflection时,我有一个关于异常处理的问题。

基本上我通过使用ContructorInfo.Invoke(new object[] { ... })来调用类的构造函数。

我将它全部包装在try / catch中,如下所示:

try
{
    preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
    Exception baseEx = e.GetBaseException();

    Utilities.Log("GetBaseException", baseEx.StackTrace);

    if (baseEx != null)
        throw baseEx;
    else
        throw e;
}

我的问题是,为什么baseEx.StackTrace不是我抛出baseEx时看到的堆栈跟踪?

我在抛出异常时看到的堆栈跟踪仅包含“constructor.Invoke()之外的跟踪”,Utilities.Log("GetBaseException", baseEx.StackTrace);向我显示“constructor.Invoke()内部的完整跟踪。”

修改

通过使用@Knaģis的答案,这是我问题的实际解决方案:

Exception baseEx = e.GetBaseException();

if (baseEx != null)
{
    throw new Exception("CreateExport Exception", baseEx);
}

2 个答案:

答案 0 :(得分:2)

执行throw baseEx;时,运行时将为抛出的异常分配新的堆栈跟踪。这与Reflection或您的特定用例无关。

如果您需要保留原始堆栈跟踪,请使用简单的throw;(不带参数) - 它会重新捕获您捕获的完全相同的异常,并保留所有详细信息:

try
{
    preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
    Exception baseEx = e.GetBaseException();
    Utilities.Log("GetBaseException", baseEx.StackTrace);

    throw;
}

答案 1 :(得分:0)

试试这个:

using System.Runtime.Serialization;

public static class ExceptionHelper
{
    public static void PreserveStackTrace(this  Exception e)
    {
        var streamingContext = new StreamingContext(StreamingContextStates.CrossAppDomain);
        var objectManager = new ObjectManager(null, streamingContext);
        var serializationInfo = new SerializationInfo(e.GetType(), new FormatterConverter());

        e.GetObjectData(serializationInfo, streamingContext);
        objectManager.RegisterObject(e, 1, serializationInfo);
        objectManager.DoFixups(); 
    }
}

并在重新抛出之前使用:

try
{
    preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
    Exception baseEx = e.GetBaseException();

    Utilities.Log("GetBaseException", baseEx.StackTrace);

    baseEx.PreserveStackTrace();

    if (baseEx != null)
        throw baseEx;
    else
        throw e;
}