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一起工作

From BinaryExpression to Expression<Func<T, bool>&g

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);