Preserving exceptions from dynamically invoked methods

c#, exception, reflection

Solution

Here's the solution I came up with. It gets the job done. I'm still interested in other answers as there might be something easier or cleaner.

- When you want the functionality of `throw;` but the exception you want to pass on is not the exception of the current `catch` block, use `throw Functional.Rethrow(e);`

- Replace `try...catch...` with `Functional.TryCatch`

- Replace `try...catch...finally...` with `Functional.TryCatchFinally`

Here's the code:

//Need a dummy type that is throwable and can hold an Exception
public sealed class RethrowException : Exception
{
    public RethrowException(Exception inner) : base(null, inner) { }
}

public static Functional
{    
    public static Exception Rethrow(Exception e)
    {
        return new RethrowException(e);
    }

    public static void TryCatch(Action _try, Action<Exception> _catch)
    {
        try { _try(); }
        catch (RethrowException e) { _catch(e.InnerException); }
        catch (Exception e) { _catch(e); }
    }

    public static T TryCatch<T>(Func<T> _try, Func<Exception, T> _catch)
    {
        try { return _try(); }
        catch (RethrowException e) { return _catch(e.InnerException); }
        catch (Exception e) { return _catch(e); }
    }

    public static void TryCatchFinally(
        Action _try, Action<Exception> _catch, Action _finally)
    {
        try { _try(); }
        catch (RethrowException e) { _catch(e.InnerException); }
        catch (Exception e) { _catch(e); }
        finally { _finally(); }
    }

    public static T TryCatchFinally<T>(
        Func<T> _try, Func<Exception, T> _catch, Action _finally)
    {
        try { return _try(); }
        catch (RethrowException e) { return _catch(e.InnerException); }
        catch (Exception e) { return _catch(e); }
        finally { _finally(); }
    }
}

Update

In .NET 4.5 there is the new `System.Runtime.ExceptionServices.ExceptionDispatchInfo` class. This can be used to capture an exception:

var capturedException = ExceptionDispatchInfo.Capture(e);

And then later this is used to resume throwing the exception:

capturedException.Throw();

Problem

- Related - Related I want to dynamically invoke a `MethodInfo` object and have any exceptions that get thrown from inside of it pass outward as if it were called normally. I have two options it seems. They're outlined below. Option 1 maintains the type of the exception thrown by `MyStaticFunction`, but the `StackTrace` is ruined because of the `throw`. Option 2 maintains the `StackTrace` of the exception, but the type of the exception is always `TargetInvocationException`. I can pull out the `InnerException` and its type, but that means that I can't write this for example: ``` try { DoDynamicCall(); } catch (MySpecialException e) { /* special handling */ } ``` Option 1: ``` void DoDynamicCall() { MethodInfo method = /*referencing MyClass method void MyStaticFunction(int x)*/; try { method.Invoke(null, new object[] { 5 }); } catch (TargetInvocationException e) { throw e.InnerException; } } ``` Option 2: ``` void DoDynamicCall() { MethodInfo method = /*referencing MyClass method void MyStaticFunction(int x)*/; method.Invoke(null, new object[] { 5 }); } ``` What I really want is for callers to `DoDynamicCall` to receive exceptions as if they had called this: ``` void DoDynamicCall() { MyClass.MyStaticFunction(5); } ``` Is there a way to get the benefits of both Option 1 and Option 2? Edit: The option I wish I had (invented special new C# keyword `rethrow` on the spot): ``` void DoDynamicCall() { MethodInfo method = /*referencing MyClass method void MyStaticFunction(int x)*/; try { method.Invoke(null, new object[] { 5 }); } catch (TargetInvocationException e) { //Magic "rethrow" keyword passes this exception //onward unchanged, rather than "throw" which //modifies the StackTrace, among other things rethrow e.InnerException; } } ``` This would also eliminate the need for this weirdo, because you could use `rethrow e;` instead: ``` try { ... } catch (Exception e) { if (...) throw; } ``` In general, it would be a way to decouple `throw;` from the requirement "I have to be directly in a catch block."

Original source

Related problems