LINQ反射表达式访问嵌套属性抛出异常的解决方法
解决嵌套LINQ Expression属性访问的TargetException问题
你的问题出在手动解析表达式树时只处理了单层属性访问,当遇到嵌套属性(比如m.Name.First)时,表达式树是多层嵌套的MemberExpression,直接用根对象Person去获取最内层属性的值自然会类型不匹配。
最简单的解决方案:编译表达式委托
其实你完全不用手动解析表达式树,直接把Expression<Func<Person, string>>编译成可执行的委托,它会自动处理所有嵌套的成员访问逻辑:
public static void OutputField(Person p, Expression<Func<Person, string>> outExpr) { // 编译表达式为委托,自动处理嵌套属性 var getValue = outExpr.Compile(); string v = getValue(p); Console.WriteLine($"value={v}"); }
这个修改后,不管是调用OutputField(person, m => m.City)还是OutputField(person, m => m.Name.First)都能正常输出结果,而且代码简洁易维护。
手动解析嵌套表达式树的方案(如果需要自定义逻辑)
如果你确实需要手动解析表达式树而不是编译,那得逐层遍历嵌套的MemberExpression,一步步计算每个成员的值:
public static void OutputField(Person p, Expression<Func<Person, string>> outExpr) { object currentValue = p; Expression currentExpr = outExpr.Body; // 遍历所有嵌套的成员访问节点 while (currentExpr is MemberExpression memberExpr) { var property = (PropertyInfo)memberExpr.Member; // 用当前值作为目标,获取下一层属性的值 currentValue = property.GetValue(currentValue, null); // 移动到上一层表达式节点 currentExpr = memberExpr.Expression; } string v = currentValue.ToString(); Console.WriteLine($"value={v}"); }
为什么原来的代码会报错?
当你传入m => m.Name.First时,表达式树的结构是:
- 最外层是
MemberExpression(对应First属性),它的Expression是另一个MemberExpression(对应Name属性) - 而
Name属性的Expression才是参数m(Person实例)
原来的代码直接拿First属性去调用prop.GetValue(p, null),相当于试图从Person实例获取First属性,这显然类型不匹配,所以抛出了TargetException。
关于你提到的"Combine lambda expressions to retrieve nested values"
这个思路本质上就是处理嵌套表达式树的遍历逻辑,上面的手动解析方案就是这个思路的具体实现——逐层拆解表达式树,依次计算每个成员的值,最终得到嵌套属性的结果。
内容的提问来源于stack exchange,提问作者John Bruestle
相关产品推荐
相关产品推荐

