将包含变量的Lambda表达式转换为字符串
本文关键字:转换 字符串 表达式 Lambda 包含 变量 | 更新日期: 2023-09-27 18:14:03
我想转换流动表达式
person.Name = "John";
Expression<Func<Person, bool>> exp = x => x.Name == person.Name && x.Age > 20;
转换成这样的字符串:
(x.Name == "John") AndAlso (x.Age > 20)
我使用exp.ToString();
方法,但结果是:
(x.Name == value(MyNamespace.MyClass+<>c__DisplayClass0).person.Name) AndAlso (x.Age > 20)
如何正确转换表达式?
问题是你的表达式在闭包中引用了一个范围内的变量,而你需要的是一个常量表达式。
您可以使用ExpressionVisitor
重写表达式树,这样它就可以消除导致常量的成员访问:
namespace FixVisitor
{
class Program
{
static void Main(string[] args)
{
var person = new Person();
person.Name = "John";
Expression<Func<Person, bool>> exp = x => x.Name == person.Name && x.Age > 20;
var modified = new FixVisitor().Visit(exp);
Console.WriteLine(modified);
}
}
class FixVisitor : ExpressionVisitor
{
bool IsMemeberAccessOfAConstant(Expression exp)
{
if (exp.NodeType == ExpressionType.MemberAccess)
{
var memberAccess = (MemberExpression) exp;
if (memberAccess.Expression.NodeType == ExpressionType.Constant)
return true;
return IsMemeberAccessOfAConstant(memberAccess.Expression);
}
return false;
}
protected override Expression VisitMember(MemberExpression node)
{
if (IsMemeberAccessOfAConstant(node) && node.Type == typeof(string))
{
var item = Expression.Lambda<Func<string>>(node);
var value = item.Compile()();
return Expression.Constant(value, typeof(string));
}
return base.VisitMember(node);
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}
要做自己想做的事,就得以人为本。命名为常量,所以我认为你必须在运行时构建表达式:
var pers = Expression.Parameter(typeof(Person), "x"); //The parameter to the expression(its type and its name)
var propName = Expression.Property(pers, "Name"); // The property "Name" of the parameter(x.Name)
var nameAsConstant = Expression.Constant(person.Name); // The value I will compare to x.Name
var equal = Expression.Equal(propName, nameAsConstant); // The comparison(x.Name == "John")
var propAge = Expression.Property(pers, "Age"); // The property "Age" of the parameter(x.Age)
var ageConstant = Expression.Constant(20); // The value I will compare to x.Age
var greater = Expression.GreaterThan(propAge, ageConstant); // The comparison(x.Age > 20)
var conditions = Expression.AndAlso(equal, greater); // Merging the expression with && [(x.Name == "John") AndAlso (x.Age > 20)]
var lambda = Expression.Lambda<Func<Person, bool>>(conditions, pers); // Build the expression
var lambdaStr = lambda.ToString(); //x => ((x.Name == "John") AndAlso (x.Age > 20))
如果你只需要((x.Name == "John") AndAlso (x.Age > 20))
,就做conditions.ToString();