从BinaryExpression到Expression <Func >
假设我有类似的东西
Expression<Func> left = x => x.SomeDateProperty; Expression<Func> right = x => dateTimeConstant; var binaryExpression = Expression.GreaterThan(left, right); Expression<Func> predicate = x => x.SomeDateProperty> dateTimeConstant;
1)如何使用binaryExpression
替换最后一行赋值的binaryExpression
? var predicate = x => binaryExpression;
不起作用。
2) right
总是一个常数,不一定是DateTime.Now。 它可能是一些更简单的Expression
吗? 例如,它不依赖于SomeType,它只是一个常量。
3)如果我将GreaterThan
作为string
,有没有办法从这个字符串到Expression
具有相同名称的方法? 通常,如果比较方法的名称是以string
forms给出的,那么如何从字符串转到实际调用Expression
类中具有相同名称的方法?
如果重要的话,它必须与LINQ to Entities一起使用。
1和2:您需要手动构建表达式树来执行此操作,编译器无法提供帮助,因为它只构造完整表示函数的现成表达式。 当你想要逐个构建函数时,这没用。
这是构建所需表达式的一种直接方式:
var argument = Expression.Parameter(typeof(SomeType)); var left = Expression.Property(argument, "SomeDateProperty"); var right = Expression.Constant(DateTime.Now); var predicate = Expression.Lambda>( Expression.GreaterThan(left, right), new[] { argument } );
您可以将其用于试驾
var param = new SomeType { SomeDateProperty = DateTime.Now.Add(TimeSpan.FromHours(-1)) }; Console.WriteLine(predicate.Compile()(param)); // "False"
3:由于二进制谓词的可能选择数量很可能非常小,您可以使用字典执行此操作:
var wordToExpression = new Dictionary> { { "GreaterThan", Expression.GreaterThan }, // etc };
然后,不是在第一个片段中对Expression.GreaterThan
进行硬编码,而是执行类似wordToExpression["GreaterThan"](left, right)
。
当然,这也可以通过reflection的标准方式完成。
使用GreaterThan
,需要指定表达式主体 ,而不是lambda本身。 不幸的是,有一个复杂因素:两个表达式中的x
不一样 。
在这种特殊情况下,你可以侥幸逃脱,因为第二个表达式不使用x
所以; 您的“1”和“2”应该通过以下方式回答:
var binaryExpression = Expression.GreaterThan(left.Body, right.Body); var lambda = Expression.Lambda>(binaryExpression, left.Parameters);
但是,要在一般情况下处理此问题,您必须重写表达式,以修复参数:
var binaryExpression = Expression.GreaterThan(left.Body, new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body)); var lambda = Expression.Lambda>(binaryExpression, left.Parameters);
有:
public class SwapVisitor : ExpressionVisitor { private readonly Expression from, to; public SwapVisitor(Expression from, Expression to) { this.from = from; this.to = to; } public override Expression Visit(Expression node) { return node == from ? to : base.Visit(node); } }
为你的“3”; 没有内置的东西; 但你可以使用reflection:
string method = "GreaterThan"; var op = typeof(Expression).GetMethod(method, BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(Expression), typeof(Expression) }, null); var rightBody = new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body); var exp = (Expression)op.Invoke(null, new object[] { left.Body, rightBody }); var lambda = Expression.Lambda>(exp, left.Parameters);