将两个前pressions(前pression<&Func键LT; T,BOOL>>) [英] Combining two expressions (Expression<Func<T, bool>>)

查看:155
本文介绍了将两个前pressions(前pression<&Func键LT; T,BOOL>>)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我型防爆pression&LT的两位前pressions; Func键< T,BOOL>> 我要采取OR,AND或NOT的这些和得到相同的类型的新的前pression

 防爆pression<&Func键LT; T,BOOL>>表达式1;
防爆pression<&Func键LT; T,BOOL>>表达式2;...//怎么办(以下code显然不会工作)这
防爆pression<&Func键LT; T,BOOL>> ANDEX pression = EXPR和表达式2


解决方案

好了,你可以使用防爆pression.AndAlso / OrElse运算等逻辑EX pressions结合起来,但问题是参数;你在表达式1和表达式2相同的 ParameterEx pression 工作吗?如果是这样,这是更容易:

  VAR体=前pression.AndAlso(expr1.Body,expr2.Body);
VAR波长=前pression.Lambda<&Func键LT; T,BOOL>>(身体,expr1.Parameters [0]);

这也是行之有效的否定单一操作:

 静态防爆pression<&Func键LT; T,BOOL>>不< T>(
    这种防爆pression<&Func键LT; T,BOOL>>表达式)
{
    返回前pression.Lambda<&Func键LT; T,BOOL>>(
        实施例pression.Not(expr.Body),expr.Parameters [0]);
}

另外,根据不同的LINQ提供程序,你也许可以将它们与调用组合:

  // OrElse运算很相似...
静态防爆pression<&Func键LT; T,BOOL>> AndAlso运算< T>(
    这种防爆pression<&Func键LT; T,BOOL>>剩下,
    防爆pression<&Func键LT; T,BOOL>>对)
{
    VAR参数=前pression.Parameter(typeof运算(T),X);
    VAR体=前pression.AndAlso(
            防爆pression.Invoke(左,参数),
            防爆pression.Invoke(右帕拉姆)
        );
    VAR波长=前pression.Lambda<&Func键LT; T,BOOL>>(机身,参数);
    返回的lambda;
}

冥冥之中,我已经得到了一些code,它重新写一个前pression树替换节点删除调用的需要,但它是相当长(我不记得在那里我把它...)


广义版本,采简单的路线:

 静态防爆pression<&Func键LT; T,BOOL>> AndAlso运算< T>(
    这种防爆pression<&Func键LT; T,BOOL>>表达式1,
    防爆pression<&Func键LT; T,BOOL>>表达式2)
{
    //需要检测它们是否使用相同的
    //参数实例;如果不是,他们需要固定
    ParameterEx pression参数= expr1.Parameters [0];
    如果(的ReferenceEquals(参数,expr2.Parameters [0]))
    {
        //简易版
        返回前pression.Lambda<&Func键LT; T,BOOL>>(
            防爆pression.AndAlso(expr1.Body,expr2.Body),参数);
    }
    //否则,保持表达式1原样并调用表达式2
    返回前pression.Lambda<&Func键LT; T,BOOL>>(
        防爆pression.AndAlso(
            expr1.Body,
            防爆pression.Invoke(表达式2,参数)),参数);
}

从.NET 4.0开始。有防爆pressionVistor类,它允许你建立前pressions是EF安全的。

 公共静态防爆pression<&Func键LT; T,BOOL>> AndAlso运算< T>(
        这种防爆pression<&Func键LT; T,BOOL>>表达式1,
        防爆pression<&Func键LT; T,BOOL>>表达式2)
    {
        变量参数=前pression.Parameter(typeof运算(T));        变种leftVisitor =新ReplaceEx pressionVisitor(expr1.Parameters [0],参数);
        VAR左= leftVisitor.Visit(expr1.Body);        变种rightVisitor =新ReplaceEx pressionVisitor(expr2.Parameters [0],参数);
        VAR右= rightVisitor.Visit(expr2.Body);        返回前pression.Lambda<&Func键LT; T,BOOL>>(
            防爆pression.AndAlso(左,右),参数);
    }    私有类ReplaceEx pressionVisitor
        :防爆pressionVisitor
    {
        私人只读防爆pression _oldValue;
        私人只读防爆pression _newValue;        公共ReplaceEx pressionVisitor(前pression属性oldValue,防爆pression newValue)以
        {
            _oldValue =属性oldValue;
            _newValue =为newValue;
        }        公共覆盖防爆pression访问(防爆pression节点)
        {
            如果(节点== _oldValue)
                返回_newValue;
            返回base.Visit(节点);
        }
    }

I have two expressions of type Expression<Func<T, bool>> and I want to take to OR, AND or NOT of these and get a new expression of the same type

Expression<Func<T, bool>> expr1;
Expression<Func<T, bool>> expr2;

...

//how to do this (the code below will obviously not work)
Expression<Func<T, bool>> andExpression = expr AND expr2

解决方案

Well, you can use Expression.AndAlso / OrElse etc to combine logical expressions, but the problem is the parameters; are you working with the same ParameterExpression in expr1 and expr2? If so, it is easier:

var body = Expression.AndAlso(expr1.Body, expr2.Body);
var lambda = Expression.Lambda<Func<T,bool>>(body, expr1.Parameters[0]);

This also works well to negate a single operation:

static Expression<Func<T, bool>> Not<T>(
    this Expression<Func<T, bool>> expr)
{
    return Expression.Lambda<Func<T, bool>>(
        Expression.Not(expr.Body), expr.Parameters[0]);
}

Otherwise, depending on the LINQ provider, you might be able to combine them with Invoke:

// OrElse is very similar...
static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> left,
    Expression<Func<T, bool>> right)
{
    var param = Expression.Parameter(typeof(T), "x");
    var body = Expression.AndAlso(
            Expression.Invoke(left, param),
            Expression.Invoke(right, param)
        );
    var lambda = Expression.Lambda<Func<T, bool>>(body, param);
    return lambda;
}

Somewhere, I have got some code that re-writes an expression-tree replacing nodes to remove the need for Invoke, but it is quite lengthy (and I can't remember where I left it...)


Generalized version that picks the simplest route:

static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr1,
    Expression<Func<T, bool>> expr2)
{
    // need to detect whether they use the same
    // parameter instance; if not, they need fixing
    ParameterExpression param = expr1.Parameters[0];
    if (ReferenceEquals(param, expr2.Parameters[0]))
    {
        // simple version
        return Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(expr1.Body, expr2.Body), param);
    }
    // otherwise, keep expr1 "as is" and invoke expr2
    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(
            expr1.Body,
            Expression.Invoke(expr2, param)), param);
}

Starting from .net 4.0. There is the ExpressionVistor class which allows you to build expressions that are EF safe.

    public static Expression<Func<T, bool>> AndAlso<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof (T));

        var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
        var left = leftVisitor.Visit(expr1.Body);

        var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
        var right = rightVisitor.Visit(expr2.Body);

        return Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(left, right), parameter);
    }



    private class ReplaceExpressionVisitor
        : ExpressionVisitor
    {
        private readonly Expression _oldValue;
        private readonly Expression _newValue;

        public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
        {
            _oldValue = oldValue;
            _newValue = newValue;
        }

        public override Expression Visit(Expression node)
        {
            if (node == _oldValue)
                return _newValue;
            return base.Visit(node);
        }
    }

这篇关于将两个前pressions(前pression&LT;&Func键LT; T,BOOL&GT;&GT;)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆