例外TargetInvocationExceptionは、Type.InvokeMemberメソッドやMethodInfo.InvokeメソッドなどMemberInfo派生クラスを介したメンバ呼び出しの際に、呼び出し先で例外が発生した場合にスローされる例外です。
呼び出したメンバで発生した例外は、TargetInvocationExceptionにラップされた上で再スローされます。 実際にメンバがスローした例外は、キャッチした例外のInnerExceptionプロパティを参照することで取得することができます。
MethodInfoを介した呼び出しでメソッドがスローした例外をキャッチする
using System;
using System.Reflection;
class C {
public void M() => throw new NotImplementedException();
}
class Sample {
static void Main()
{
var t = typeof(C);
var inst = Activator.CreateInstance(t);
var m = t.GetMethod("M");
try {
// MethodInfo.Invokeを使ってメソッドを呼び出す (呼び出し先で例外が発生する)
m.Invoke(inst, null);
}
// 呼び出したメソッドで例外が発生した場合、TargetInvocationExceptionがスローされる
catch (TargetInvocationException ex) {
Console.WriteLine(ex);
Console.WriteLine();
// InnerExceptionプロパティを参照してメソッドが実際にスローした例外を取得する
Console.WriteLine("actual exception type: {0}", ex.InnerException.GetType());
}
}
}
実行結果
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NotImplementedException: The method or operation is not implemented. at C.M() --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) at Sample.Main() actual exception type: System.NotImplementedException
MethodInfo.Invokeのほかにも、PropertyInfo.GetValue/SetValueやConstructorInfo.Invokeによってプロパティやコンストラクタなどを呼び出した結果例外が発生した場合も、同様にTargetInvocationExceptionがスローされます。
なお、BindingFlags.DoNotWrapExceptionsを指定することにより、例外が発生した場合でもTargetInvocationExceptionにラップさせず、発生した例外そのものをキャッチすることもできます。