如何让C# Expression表达式ToString返回含实际变量值的结果?
问题描述
我有如下类:
public class TestClass { public int TestProperty { get; set; } }
我有如下代码:
int x = 1; Expression<Func<TestClass, bool>> predicate = c => c.TestProperty == x; Console.WriteLine(predicate.ToString());
调用 predicate.ToString() 返回的结果是 c => (c.TestProperty == value(Program+<>c__DisplayClass0_0).x)
请问是否有办法解析该Expression表达式,使其返回 c => (c.TestProperty == 1)
注:无法通过如下方式直接创建表达式
Expression<Func<TestClass, bool>> predicate = c => c.TestProperty == 1;
解决方案
可以通过实现自定义表达式访问器,替换表达式中捕获的闭包变量为实际值,从而得到目标字符串。
实现自定义表达式访问器
继承 ExpressionVisitor 重写 VisitMember 方法,识别闭包类的字段访问并替换为常量:
using System.Reflection; using System.Linq.Expressions; public class ClosureVariableReplacer : ExpressionVisitor { protected override Expression VisitMember(MemberExpression node) { // 判断是否是闭包类的字段访问 if (node.Expression is ConstantExpression closureInstanceExpr && node.Member is FieldInfo field) { // 获取字段的实际值 var fieldValue = field.GetValue(closureInstanceExpr.Value); // 替换为对应类型的常量表达式 return Expression.Constant(fieldValue, field.FieldType); } return base.VisitMember(node); } }
使用访问器处理表达式
将原表达式传入访问器,得到替换后的表达式再调用 ToString():
int x = 1; Expression<Func<TestClass, bool>> predicate = c => c.TestProperty == x; var replacer = new ClosureVariableReplacer(); var processedExpr = replacer.Visit(predicate) as Expression<Func<TestClass, bool>>; Console.WriteLine(processedExpr.ToString()); // 输出结果:c => (c.TestProperty == 1)
原理说明
Lambda捕获外部变量时,编译器会自动生成一个闭包类,把捕获的变量包装成该类的字段。自定义访问器会遍历表达式树,找到这类访问闭包字段的节点,读取字段的实际值并替换为常量表达式,最终生成的表达式字符串就会显示具体数值而非闭包引用。
内容的提问来源于stack exchange,提问作者Ghyath Serhal
相关产品推荐
相关产品推荐

