Reflection MethodInfo.Invoke()从方法内部捕获异常

时间:2010-11-07 09:52:21

标签: c# exception reflection methods invoke

我呼吁MethodInfo.Invoke()通过反射执行一个函数。调用包含在try/catch块中,但它仍然不会捕获我正在调用的函数抛出的异常。

我收到以下消息:

  

用户未处理异常。


为什么MethodInfo.Invoke()阻止异常被捕获到Invoke()之外? 我该如何绕过它?

2 个答案:

答案 0 :(得分:28)

编辑:据我了解你的问题,问题纯粹是一个IDE;你不喜欢VS将MethodInfo的调用引发的异常视为未被捕获,当它显然不是时。您可以在此处阅读有关如何解决此问题的信息:Why is TargetInvocationException treated as uncaught by the IDE?它似乎是一个错误/设计;但不管怎样,答案中都列出了不错的解决方法。

在我看来,你有几个选择:

  1. 您可以使用MethodInfo.Invoke,抓住TargetInvocationException并检查其InnerException属性。您将必须解决该问题中提到的IDE问题。

  2. 您可以从Delegate中创建适当的MethodInfo并调用它。使用此技术,抛出的异常将不会被包装。此外,这种方法 似乎可以很好地与调试器一起使用;我没有得到任何“未捕获的例外”弹出窗口。

  3. 这是一个突出两种方法的例子:

    class Program
    {
        static void Main()
        {
            DelegateApproach();
            MethodInfoApproach();
        }
    
        static void DelegateApproach()
        {
            try
            {
                Action action = (Action)Delegate.CreateDelegate
                                       (typeof(Action), GetMethodInfo());
                action();
            }
            catch (NotImplementedException nie)
            {
    
            }
         }
    
        static void MethodInfoApproach()
        {
            try
            {
                GetMethodInfo().Invoke(null, new object[0]);
            }
            catch (TargetInvocationException tie)
            {
                if (tie.InnerException is NotImplementedException)
                {
    
    
                }
            }
        }
    
        static MethodInfo GetMethodInfo()
        {
            return typeof(Program)
                    .GetMethod("TestMethod", BindingFlags.NonPublic | BindingFlags.Static);
        }    
    
        static void TestMethod()
        {
            throw new NotImplementedException();
        }
    }
    

答案 1 :(得分:19)

你是如何捕捉异常的?通常,对Invoke()的调用抛出的是System.Reflection.TargetInvocationException的包装异常实例。您所追求的实际例外情况将在InnerException

try
{
    method.Invoke(target, params);
}
catch (TargetInvocationException ex)
{
    ex = ex.InnerException; // ex now stores the original exception
}