反射调用方法抛出指定异常无法被特定Catch块捕获的问题
核心原因
这个问题是反射调用的经典坑——当你用MethodInfo.Invoke()执行方法时,.NET会把目标方法内部抛出的所有异常**包装成TargetInvocationException**再抛出。你写的catch (System.UnauthorizedAccessException)根本抓不到原始异常,因为它被藏在TargetInvocationException.InnerException里了,自然就落到了通用的Exception catch块中。
解决方案
这里有两种实用的解决方式,你可以根据项目的.NET版本和代码风格选择:
方案1:捕获TargetInvocationException并检查内部异常
修改你的catch块逻辑,先捕获包装异常,再判断内部的原始异常类型:
try { var type = message.Form.GetObjTypeOf(typeof(BaseEntity)); MethodInfo updateFormStatusMethod = typeof(IFormService).GetMethod("UpdateFormStatus"); MethodInfo generic = updateFormStatusMethod.MakeGenericMethod(type); var result = (bool)generic.Invoke(performanceformService, new object[] { message }); } catch (TargetInvocationException tie) { // 检查内部异常是否是我们要处理的未授权异常 if (tie.InnerException is UnauthorizedAccessException) { // 这里处理未授权的业务逻辑 Console.WriteLine("捕获到未授权访问异常"); } else { // 非目标异常可以选择重新抛出,避免隐藏问题 throw tie.InnerException; } } catch (System.Exception ex) { // 处理其他非包装的异常 }
方案2:用dynamic避免异常包装(.NET 4.5+)
如果你的项目基于.NET 4.5及以上版本,可以借助dynamic来调用泛型方法,这样反射的异常包装机制会被跳过,原始异常会直接抛出:
try { var type = message.Form.GetObjTypeOf(typeof(BaseEntity)); MethodInfo updateFormStatusMethod = typeof(IFormService).GetMethod("UpdateFormStatus"); MethodInfo generic = updateFormStatusMethod.MakeGenericMethod(type); // 用dynamic调用,绕过TargetInvocationException包装 dynamic result = generic.Invoke(performanceformService, new object[] { message }); // 需要强转返回值的话,在这里处理 bool boolResult = (bool)result; } catch (System.UnauthorizedAccessException) { // 现在这个catch块就能正常捕获到目标异常了! } catch (System.Exception ex) { // 处理其他异常 }
小提示
- 方案2的
dynamic写法更简洁,但要注意类型安全,强转返回值时最好做必要的校验。 - 不管用哪种方案,都不要随意吞掉非预期的异常,必要时重新抛出,避免隐藏潜在的代码问题。
内容的提问来源于stack exchange,提问作者M-Sha
相关产品推荐
相关产品推荐

