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."