使用constructorinfo . invoke时的堆栈跟踪混淆

本文关键字:跟踪 堆栈 constructorinfo invoke 使用 | 更新日期: 2023-09-27 17:53:16

大家好,

在c#中处理。net反射时,我有一个关于异常处理的问题。

基本上,我通过使用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抛出时的StackTrace ?

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

编辑:

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

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

使用constructorinfo . invoke时的堆栈跟踪混淆

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

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

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

try this:

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