正在将选择器表达式转换为谓词表达式

本文关键字:表达式 转换 谓词 选择器 | 更新日期: 2023-09-27 18:24:09

我需要一种方法将选择器表达式转换为谓词表达式

private Expression<Func<T, TKey>> PrimaryKeySelector { get; set; }
private ISpecification<T> GetByPrimaryKeySpecification(TKey key) {
   lambda = ... // some magic, also unicorns
   return new ExpressionSpecification(lambda);
}

在第一次尝试中,我使用Expression.Equal构建了谓词表达式,但这会导致分析该表达式的查询提供程序出现问题(例如,由于未知的Equal语句,NHibernate失败)。此外,我看到了创建新ParameterExpression并通过调用选择器表达式来使用其结果的解决方案,但我觉得这很糟糕,因为1)性能和2)参数表达式已经包含在选择表达式

有什么建议吗?

正在将选择器表达式转换为谓词表达式

这里要做的是将一个表达式与另一个表达式组合。使用函数执行此操作非常容易;用表达式做这件事需要更多的工作。

您可以做的是用第一个函数选择器的主体替换第二个表达式谓词的所有参数实例。

public static Expression<Func<TFirstParam, TResult>>
    Compose<TFirstParam, TIntermediate, TResult>(
    this Expression<Func<TFirstParam, TIntermediate>> first,
    Expression<Func<TIntermediate, TResult>> second)
{
    var param = Expression.Parameter(typeof(TFirstParam), "param");
    var newFirst = first.Body.Replace(first.Parameters[0], param);
    var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
    return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}

这依赖于以下方法来用另一个表达式替换一个表达式的所有实例:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

最后一个缺失的难题是,您将无法使用==运算符在泛型方法中比较您的值,因为您无法确定该类型覆盖了==运算符;您需要手动构建等式表达式:

public static Expression<Func<T, bool>> EqualsValue<T>(T value)
{
    var param = Expression.Parameter(typeof(T));
    var body = Expression.Equal(param, Expression.Constant(value));
    return Expression.Lambda<Func<T, bool>>(body, param);
}

这允许你写:

return PrimaryKeySelector.Compose(EqualsValue(key));

至于你对性能的担忧,不要担心。你建立这样一个表达式树所花费的时间将比你用它们发出的网络请求慢很多数量级。在表达式操作上多花一点时间甚至不会对应用程序的性能产生可衡量的影响;它将远低于网络请求的噪声