C#中如何获取FieldExpression实际值?Expression转SQL Where子句遇阻
解决Expression引用外部变量时获取值的问题
当你遇到表达式引用外部变量(比如p => p.Category == categoryName)时,编译器会把外部变量包装到一个自动生成的闭包类字段里,所以表达式右侧的categoryName对应的是MemberExpression而非ConstantExpression。你需要解析这个成员表达式的实例和字段才能拿到实际值,不用纠结直接编译整个Func的方式(当然编译可以作为兜底方案,但解析更高效)。
核心处理思路
写一个递归解析方法,覆盖两种常见场景:
- 直接的常量表达式,直接返回值
- 成员访问表达式(闭包类的字段/属性),先获取成员所属的实例,再读取字段/属性的值
- 兜底用编译表达式的方式获取值(应对更复杂的嵌套场景)
代码实现
private static object GetValue(Expression expression) { // 处理常量表达式 if (expression is ConstantExpression constantExpr) { return constantExpr.Value; } // 处理闭包类的字段/属性访问 if (expression is MemberExpression memberExpr) { // 递归获取成员所属的实例值 var instance = GetValue(memberExpr.Expression); if (memberExpr.Member is FieldInfo field) { return field.GetValue(instance); } if (memberExpr.Member is PropertyInfo prop) { return prop.GetValue(instance); } } // 兜底方案:编译表达式获取值 var lambda = Expression.Lambda(expression).Compile(); return lambda.DynamicInvoke(); }
在转换器中的使用示例
当处理二元运算符(比如==、>=)时,对右侧表达式调用GetValue方法就能拿到实际变量值,再转成SQL对应的字面量:
// 假设binaryExpr是二元表达式(比如Equal) var rightValue = GetValue(binaryExpr.Right); // 处理字符串的SQL转义,避免注入 var sqlRightValue = rightValue is string str ? $"N'{str.Replace("'", "''")}'" : rightValue.ToString(); // 拼接成SQL片段,比如:Category = N'Electronics' var sqlSegment = $"{GetMemberName(binaryExpr.Left)} = {sqlRightValue}";
关于之前编译Func失败的说明
如果是直接编译整个Expression<Func<T,bool>>,其实是可以正常执行的;但如果单独编译右侧的成员表达式,必须把它包装成无参数的Lambda再编译,就像上面GetValue方法里做的那样,否则会因为缺少上下文导致编译失败。
内容的提问来源于stack exchange,提问作者Ido Dvir
相关产品推荐
相关产品推荐

