代码之家  ›  专栏  ›  技术社区  ›  berko

如何组合现有的LINQ表达式

  •  11
  • berko  · 技术社区  · 17 年前

    我想组合两个LINQ表达式的结果。它们以形式存在

    Expression<Func<T, bool>>
    

    所以我要组合的两个基本上是一个参数(类型T)的委托,这两个参数都返回一个布尔值。我想要的结果是布尔值的逻辑评估。我可能会将其作为扩展方法实现,因此我的语法如下:

    Expression<Func<User, bool>> expression1 = t => t.Name == "steve";
    Expression<Func<User, bool>> expression2 = t => t.Age == 28;
    Expression<Func<User, bool>> composedExpression = expression1.And(expression2);
    

    稍后在我的代码中,我想计算组合表达式

    var user = new User();
    bool evaluated = composedExpression.Compile().Invoke(user);
    

    我提出了一些不同的想法,但我担心这比我希望的要复杂。怎么做到的?

    3 回复  |  直到 14 年前
        1
  •  17
  •   Dan Atkinson    14 年前

    下面是一个例子:

    var user1 = new User {Name = "steve", Age = 28};
    var user2 = new User {Name = "foobar", Age = 28};
    
    Expression<Func<User, bool>> expression1 = t => t.Name == "steve";
    Expression<Func<User, bool>> expression2 = t => t.Age == 28;
    
    var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
    
    var result = Expression.Lambda<Func<User, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
    
    Console.WriteLine(result.Compile().Invoke(user1)); // true
    Console.WriteLine(result.Compile().Invoke(user2)); // false
    

    您可以通过扩展方法重用此代码:

    class User
    {
      public string Name { get; set; }
      public int Age { get; set; }
    }
    
    public static class PredicateExtensions
    {
      public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,Expression<Func<T, bool>> expression2)
      {
        InvocationExpression invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>());
    
        return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters);
      }
    }
    
    class Program
    {
      static void Main(string[] args)
      {
        var user1 = new User {Name = "steve", Age = 28};
        var user2 = new User {Name = "foobar", Age = 28};
    
        Expression<Func<User, bool>> expression1 = t => t.Name == "steve";
        Expression<Func<User, bool>> expression2 = t => t.Age == 28;
    
        var result = expression1.And(expression2);
    
        Console.WriteLine(result.Compile().Invoke(user1));
        Console.WriteLine(result.Compile().Invoke(user2));
      }
    }
    
        2
  •  5
  •   Jan Kelnar    17 年前

    您也可以使用LinqKit,它可以为您完成所有这些工作。 http://www.albahari.com/nutshell/linqkit.aspx

        3
  •  1
  •   Konrad Rudolph    17 年前

    你为什么不直接用 Expression.And 并处理结果 BinaryExpression ?

    Expression<Func<T, bool>> expr1 = t => t.Name == "steve";
    Expression<Func<T, bool>> expr2 = t => t.Age == 28;
    Expression composed = Expression.And(expr1.Body, expr2.Body);
    

    当然,您可以将其绑定到lambda中以获得所需的签名,但这是昂贵的,应该只执行此操作。 一旦 ,不是多次:

    Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(
        expr, Expression.Parameter(typeof(T), "t")
    );
    

    /编辑:当然可以按如下方式组合lambda,但这涉及到冗余编译和函数调用:

    Expression<Func<string, bool>> z = t => expr1.Compile()(t) && expr2.Compile()(t);
    

    该死,维修停机。必须重新输入整个帖子。- -

    /编辑:阿库是对的。你必须调用 expr2 另外,否则编译器将找不到参数引用。