扩展访问表达式以检查值 [英] Extending an access expression to check for value

查看:43
本文介绍了扩展访问表达式以检查值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正试图与表达式树搏斗,以使魔术发生,但我不断出错.

I'm currently trying to wrestle with expression trees to make a bit of magic happen, but I keep hitting error after error.

我的某些域对象(实体框架)上有一些这样的属性

I've got some properties like this on some of my domain objects (Entity Framework)

Expression<Func<DomainObject, LinkedDomainObject>> IncludeExpr
{
   get {
      return o => o.SomeLinkedObject;
   }
}

和另一个用于检查链接对象在某些属性(例如ID)上是否相等的表达式.

and another expression that checks that linked object for equality on some property (e.g. ID).

我确实有一个表达式,该表达式还检查了链接对象是否为空,这样我可以通过反转空检查表达式来组成一个 NotNull Matched ID 表达式并将其通过 AndAlso 与ID检查表达式进行组合.

I did have an expression that also checked that linked object for being null, and that way I could compose a NotNull and Matched ID expression by inverting the null check expression and combining it via AndAlso with the ID check expression.

我想使用 o =>o.SomeLinkedObject 表达式和 linkedObject =>linkedObject.ID == idVar 表达式并将它们混在一起以有效地获得:

I want to take the o => o.SomeLinkedObject expression and linkedObject => linkedObject.ID == idVar expressions and mash them together to effectively get:

o =>o.LinkedObject!= null&&o.LinkedObject.Id == idVar

但是我无法终生确定如何基于这两个单独的表达式将表达式树组合在一起.

But I can't for the life of me work out how I'd get an expression tree together based on those two separate expressions.

推荐答案

我们可以花一些时间来创建一个帮助程序方法,该方法可以使解决此问题变得非常简单.如果我们创建一个使我们能够像编写委托一样容易地编写表达式的方法,这将变得非常容易.我们的 Compose 方法将接受一个表达式,另一个将获取第一个输出并将其转换为其他内容的表达式,从而创建一个新表达式,该表达式可将第一个输入的类型转换为一个表达式.第二个输出:

We can take a moment to create a helper method that can make solving this problem very straightforward. If we create a method that lets us compose expressions as easily as we can compose delegates, this becomes very easy. Our Compose method will accept an expression, and another that takes the output of the first and transforms it into something else, creating a new expression that can transform something of the type of the input of the first into the output of the second:

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

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

This is dependent on the following method to replace all instances of one expression with another:

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

现在,我们可以非常轻松地创建一个 IsNotNull 转换:

Now we can create an IsNotNull transformation very easily:

public static Expression<Func<TSource, bool>> IsNotNull<TSource, TKey>(
    this Expression<Func<TSource, TKey>> expression)
{
    return expression.Compose(key => key != null);
}

对于,将两个表达式组合在一起,如果使用LINQ查询提供程序,最简单的选择是仅对每个表达式分别调用 Where ,如果可以的话.如果没有,则可以使用 PrediacteBuilder 将两个表达式一起 And Or :

As for And-ing two expressions together, the easiest option if using a LINQ query provider is to just call Where on each expression separately, if that's an option. If not, you can use a PrediacteBuilder to And or Or two expressions together:

public static class PredicateBuilder
{
    public static Expression<Func<T, bool>> True<T>() { return f => true; }
    public static Expression<Func<T, bool>> False<T>() { return f => false; }

    public static Expression<Func<T, bool>> Or<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var secondBody = expr2.Body.Replace(
            expr2.Parameters[0], expr1.Parameters[0]);
        return Expression.Lambda<Func<T, bool>>
              (Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
    }

    public static Expression<Func<T, bool>> And<T>(
        this Expression<Func<T, bool>> expr1,
        Expression<Func<T, bool>> expr2)
    {
        var secondBody = expr2.Body.Replace(
            expr2.Parameters[0], expr1.Parameters[0]);
        return Expression.Lambda<Func<T, bool>>
              (Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
    }
}

这篇关于扩展访问表达式以检查值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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