使用C# Expression扩展方法获取PropertyInfo时遭遇System.InvalidCastException异常求助
解决System.InvalidCastException:解析含方法调用的表达式树问题
问题根源
你的GetPropertyInfo扩展方法只处理直接属性访问的表达式(比如x => x.PropertyName),但你调用时传入的表达式包含了链式方法调用:x => x.SipKpiCriteria.Select(y => y.EvaluationMethod).FirstOrDefault()。
此时表达式的Body是一个MethodCallExpression(对应FirstOrDefault()调用),而非你预期的MemberExpression或包裹它的UnaryExpression。当代码尝试把MethodCallExpression强制转换为UnaryExpression时,就抛出了InvalidCastException。
两种解决方案
方案1:调整调用表达式(推荐,符合属性信息获取的初衷)
如果你的目标是获取EvaluationMethod这个属性的PropertyInfo,直接传入指向该属性的表达式即可,不需要包含集合操作方法:
// 如果是针对集合中的元素属性 .AddControl(y => y.EvaluationMethod) // 如果需要关联到父对象,确保是直接属性访问而非方法调用 // 示例:假设SipKpiCriteria是单个对象而非集合 .AddControl(x => x.SipKpiCriteria.EvaluationMethod)
方案2:扩展方法支持解析嵌套方法调用(保留现有调用方式时使用)
如果你必须保留Select+FirstOrDefault的链式调用,需要修改扩展方法来遍历表达式树,提取最内层的属性信息:
public static PropertyInfo GetPropertyInfo<T, T2>(this Expression<Func<T, T2>> propertyLambda) { Expression currentBody = propertyLambda.Body; // 处理值类型装箱产生的UnaryExpression while (currentBody is UnaryExpression unaryExpr) { currentBody = unaryExpr.Operand; } // 遍历所有MethodCallExpression,定位到最内层的属性访问 while (currentBody is MethodCallExpression methodCallExpr) { // 针对Select/FirstOrDefault这类方法,取第一个参数作为下一层表达式 currentBody = methodCallExpr.Arguments[0]; // 再次检查并处理UnaryExpression if (currentBody is UnaryExpression innerUnary) { currentBody = innerUnary.Operand; } } // 验证最终表达式是否为属性访问 if (currentBody is MemberExpression memberExpr && memberExpr.Member is PropertyInfo property) { return property; } throw new ArgumentException("传入的表达式不是有效的属性访问表达式", nameof(propertyLambda)); }
这个版本的方法会逐层解析表达式树,跳过方法调用节点,最终提取到EvaluationMethod的PropertyInfo。
关键注意事项
- 始终先通过
is关键字判断表达式类型,再进行转换,避免强制转换导致的异常; - 明确你需要获取的是哪个属性的信息,不要在表达式中混入无关的方法调用,这会增加表达式解析的复杂度。
内容的提问来源于stack exchange,提问作者Vimalkumar
相关产品推荐
相关产品推荐

