反射调用SetValue时丢失原始异常,如何获取原异常用于日志记录?
问题:反射调用SetValue时无法捕获属性Setter的原始异常
使用反射通过PropertyInfo.SetValue()给对象属性批量赋值时,属性setter抛出的原始异常(如示例中的ArgumentException)会被.NET包装为TargetInvocationException,导致日志仅显示通用错误信息“Exception has been thrown by the target of an invocation.”,无法获取原始异常的具体详情。
原代码片段
try { PropertyInfo piInstance = MBtype.GetProperty(columnlist[intColumn]); piInstance.SetValue(newMailbox, CurrentRow[intColumn]); } catch (Exception ex) { HelpFunc.writeToLog($"Error: '{ex.Message}'", "Error"); }
Setter中的原始异常代码
throw new ArgumentException($"{value} must be valid email address", value);
解决方案
反射调用的SetValue()方法会将目标方法抛出的所有异常包装到TargetInvocationException的InnerException属性中,因此只需提取该属性即可获取原始异常信息。以下是两种可行的处理方式:
方式1:直接捕获TargetInvocationException
优先捕获反射特有的包装异常,直接提取原始异常:
try { PropertyInfo piInstance = MBtype.GetProperty(columnlist[intColumn]); piInstance.SetValue(newMailbox, CurrentRow[intColumn]); } catch (TargetInvocationException tiex) { // 优先取InnerException,为空则用自身 Exception originalException = tiex.InnerException ?? tiex; // 记录原始异常的消息 HelpFunc.writeToLog($"Error: '{originalException.Message}'", "Error"); // 可选:记录完整异常信息(含栈跟踪)便于排查 // HelpFunc.writeToLog($"Full error details:\n{originalException.ToString()}", "Error"); } catch (Exception ex) { // 处理其他非反射引发的异常 HelpFunc.writeToLog($"Error: '{ex.Message}'", "Error"); }
方式2:递归获取根异常
如果存在多层异常包装的情况,可以通过辅助方法递归获取最内层的原始异常:
// 辅助方法:获取最内层的原始异常 private static Exception GetRootException(Exception ex) { while (ex.InnerException != null) { ex = ex.InnerException; } return ex; } // 使用示例 try { PropertyInfo piInstance = MBtype.GetProperty(columnlist[intColumn]); piInstance.SetValue(newMailbox, CurrentRow[intColumn]); } catch (Exception ex) { Exception rootException = GetRootException(ex); HelpFunc.writeToLog($"Error: '{rootException.Message}'", "Error"); }
说明
TargetInvocationException是.NET反射机制专门用于包装目标方法异常的类型,其InnerException必然包含原始抛出的异常(除非原始异常本身为空)。- 日志记录时建议保留完整的异常信息(如
ToString()的结果),这包含了异常类型、消息、栈跟踪等关键信息,能大幅提升问题排查效率。
内容的提问来源于stack exchange,提问作者user3844416
相关产品推荐
相关产品推荐

