Dynamic LINQ Where Clauses -- PredicateBuilder

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Curtis Rutland
    Recognized Expert Specialist
    • Apr 2008
    • 3264

    #1

    Dynamic LINQ Where Clauses -- PredicateBuilder

    This isn't a full-blown article, just a quickie. But I couldn't pass up the opportunity to share this insight with people, because it made my coding life sooooooo much easier.



    Its usefulness is situational, but I found it most valuable when I was building a searching application. I had no idea which parameters a user might include in their search. I didn't want to string-build a select statement, because I'd already created my LINQ to SQL classes, and I didn't want to do dynamic LINQ because to me the whole point of LINQ is type safety and IntelliSense.

    So I found the PredicateBuilde r. My favorite part of this is that it's not some big library that you have to download and include. It's a few lines of code that you can just paste into your own project:

    Code:
    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Collections.Generic;
     
    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 invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
        return Expression.Lambda<Func<T, bool>>
              (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
      }
     
      public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
                                                           Expression<Func<T, bool>> expr2)
      {
        var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
        return Expression.Lambda<Func<T, bool>>
              (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
      }
    }
    Add a namespace and dump that into your project, and you can use it.

    The article explains how to use it better than I could. I did find one odd behavior: using foreach loops.

    You would normally do this:
    Code:
    foreach(string s in stringCollection)
    {
        whereClause = whereClause.Or(p => p.SomeString == s);
    }
    However, for some reason, it seems to copy the pointer to "s" or something, and you end up with all the Or statements using the last value of s. To fix this, you do:
    Code:
    foreach(string s in stringCollection)
    {
        string temp = s;
        whereClause = whereClause.Or(p => p.SomeString == temp);
    }
    Other than that, it works great.
Working...