从调用Invoke(反射)中获取正确的异常类型。
从调用Invoke(反射)中获取正确的异常类型。
在我们的集成项目中,我们使用反射动态委托给一系列特定的处理器对象。
var genericType = typeof(IMessageProcessor<>).MakeGenericType(parseResponse.DomainMessage.GetType()); var miProcessMessage = genericType.GetMethod("ProcessMessage"); miProcessMessage.Invoke(processor, new object[] { parseResponse.DomainMessage });
现在,在某些情况下,其中一个处理器需要抛出一个特定的异常,例如当他在预期位置找不到文件时。
throw new ResourceNotFoundException(string.Format("无法找到文件 {0}", filePath));
我们的处理器想要检查此异常,以确定是否需要重试或中止处理(基于一个与此无关的基于时间的机制)。
catch(ResourceNotFoundException ex) { // 做一些操作 }
问题在于,调用似乎"吞噬"了特定的ResourceNotFoundException,并重新抛出一个说"通过调用的目标引发了异常"的System.Exception。
是否有办法通过反射保留ResourceNotFoundException实际上被抛出而不是Exception的事实?
问题的原因是在使用反射调用MethodBase.Invoke(Object, Object[])
方法时,如果被调用方法抛出异常,那么该异常会被包装在一个TargetInvocationException
中。为了获取到原始的异常类型,需要访问内部异常并进行处理或将其重新抛出以在堆栈中继续处理。
解决方法是使用try-catch块来捕获可能抛出的TargetInvocationException
,然后通过访问内部异常InnerException
来获取原始的异常类型。下面是一个示例代码:
var genericType = typeof(IMessageProcessor<>).MakeGenericType(parseResponse.DomainMessage.GetType()); var miProcessMessage = genericType.GetMethod("ProcessMessage"); try { miProcessMessage.Invoke(processor, new object[] { parseResponse.DomainMessage }); catch (TargetInvocationException ex) { throw ex.InnerException; }
需要注意的是,这种方法会替换内部异常的堆栈跟踪信息。如果想要保留原始异常的堆栈跟踪信息,可以参考Stack Overflow上这个答案中描述的(在技术上不支持的)方法。
另外需要注意的是,对于内置的异常类型,如SqlException
或TransactionException
,它们并不会被包装在TargetInvocationException
中,因此可以直接在它们自己的异常块中处理。而对于其他异常类型,需要查看内部异常的类型来进行处理。