首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将选择器表达式转换为谓词表达式

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

Stack Overflow用户
提问于 2014-09-24 13:52:25
回答 1查看 713关注 0票数 0

我需要一种将选择器表达式转换为谓词表达式的方法,以便将其连同一些参数传递给查询提供程序。

代码语言:javascript
复制
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构建了谓词表达式,但是这给分析表达式的查询提供程序带来了问题(例如,NHibernate由于未知的Equal语句而失败)。另外,我看到了创建新ParameterExpression并通过调用选择器表达式使用选择器表达式的结果的解决方案,但是我觉得这很糟糕,因为1)性能和2)参数表达式已经包含在选择器表达式中。

有什么建议吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-24 14:09:20

你在这里要做的是用另一个表达式组成一个表达式。使用函数进行此操作非常容易;使用表达式进行此操作需要做更多的工作。

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

代码语言:javascript
复制
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);
}

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

代码语言:javascript
复制
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);
    }
}

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

代码语言:javascript
复制
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);
}

这使您可以编写:

代码语言:javascript
复制
return PrimaryKeySelector.Compose(EqualsValue(key));

至于你对表现的担忧,不要担心。构建像这样的表达式树所花费的时间将比您将使用它们进行的网络请求慢很多数量级。在表达式操作上花费一些额外的时间甚至不会对应用程序的性能产生可衡量的影响;它将大大低于网络请求的噪音。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26018685

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档