From BinaryExpression to Expression<Func<T, bool>&g
本文关键字:lt bool gt Func Expression BinaryExpression From to | 更新日期: 2023-09-27 18:15:44
假设我有一个像
Expression<Func<SomeType, DateTime>> left = x => x.SomeDateProperty;
Expression<Func<SomeType, DateTime>> right = x => dateTimeConstant;
var binaryExpression = Expression.GreaterThan(left, right);
Expression<Func<SomeType, bool>> predicate =
x => x.SomeDateProperty> dateTimeConstant;
1)如何将最后一行赋值的右手替换为使用binaryExpression
的东西?var predicate = x => binaryExpression;
不工作
2) right
总是一个常数,不一定是DateTime.Now。会不会是更简单的Expression
类型?例如,它不依赖于SomeType,它只是一个常量。
3)如果我有GreaterThan
作为string
,是否有办法从这个字符串到Expression
中同名的方法?一般来说,如果比较方法的名称作为string
给出,我如何从字符串到实际调用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<Func<SomeType, bool>>(
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<string, Func<Expression, Expression, BinaryExpression>>
{
{ "GreaterThan", Expression.GreaterThan },
// etc
};
然后,在第一个代码片段中不是硬编码Expression.GreaterThan
,而是做wordToExpression["GreaterThan"](left, right)
。
当然,这也可以通过反射的标准方式来实现。
当您使用GreaterThan
时,您需要指定表达式 body ,而不是lambda本身。不幸的是,有一个复杂的问题:两个表达式中的x
不是同一个。
在这个特殊的的情况下,您可以侥幸逃脱,因为第二个表达式没有使用x
;你的"1"answers"2"应该这样回答:
var binaryExpression = Expression.GreaterThan(left.Body, right.Body);
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression,
left.Parameters);
然而,要在一般情况下处理这个问题,您必须重写一个表达式,以固定参数:
var binaryExpression = Expression.GreaterThan(left.Body,
new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body));
var lambda = Expression.Lambda<Func<SomeType, bool>>(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";没有任何内在的东西;不过,您可以使用反射:
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<Func<SomeType, bool>>(exp, left.Parameters);