Martin Dandanell
Martin Dandanell

Reputation: 851

Stacktrace confusion when using ContructorInfo.Invoke

Hi all you clever guys,

I have a question regarding exception handling when dealing with .NET Reflection in C#.

Basically I call a constructor on a class through the use of ContructorInfo.Invoke(new object[] { ... }).

I wrap it all in a try/catch like this:

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

My question is that why is baseEx.StackTrace not the stacktrace I see when the baseEx is thrown?

The stacktrace I see when throwing the exception does only contain a trace "outside of" constructor.Invoke() whilst Utilities.Log("GetBaseException", baseEx.StackTrace); shows me the full trace "inside of" constructor.Invoke().

EDIT:

By using the answer of @Knaģis, here is the actual solution to my problem:

Exception baseEx = e.GetBaseException();

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

Upvotes: 1

Views: 83

Answers (2)

arndtdv
arndtdv

Reputation: 111

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

and use before rethrow:

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

Upvotes: 0

Knaģis
Knaģis

Reputation: 21485

When you do throw baseEx; the runtime will assign a new stack trace for the exception thrown. This has nothing to do with Reflection or your specific use case.

If you need to preserve the original stack trace, use a simple throw; (without an argument) - it rethrows the exact same exception you caught, preserving all details:

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

    throw;
}

Upvotes: 2

Related Questions