By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,984 Members | 1,016 Online
Bytes IT Community
Submit an Article
Got Smarts?
Share your bits of IT knowledge by writing an article on Bytes.

Dynamic LINQ Where Clauses -- PredicateBuilder

Curtis Rutland
Expert 2.5K+
P: 3,256
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 PredicateBuilder. 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:

Expand|Select|Wrap|Line Numbers
  1. using System;
  2. using System.Linq;
  3. using System.Linq.Expressions;
  4. using System.Collections.Generic;
  6. public static class PredicateBuilder
  7. {
  8.   public static Expression<Func<T, bool>> True<T> ()  { return f => true;  }
  9.   public static Expression<Func<T, bool>> False<T> () { return f => false; }
  11.   public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
  12.                                                       Expression<Func<T, bool>> expr2)
  13.   {
  14.     var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
  15.     return Expression.Lambda<Func<T, bool>>
  16.           (Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
  17.   }
  19.   public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
  20.                                                        Expression<Func<T, bool>> expr2)
  21.   {
  22.     var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
  23.     return Expression.Lambda<Func<T, bool>>
  24.           (Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
  25.   }
  26. }
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:
Expand|Select|Wrap|Line Numbers
  1. foreach(string s in stringCollection)
  2. {
  3.     whereClause = whereClause.Or(p => p.SomeString == s);
  4. }
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:
Expand|Select|Wrap|Line Numbers
  1. foreach(string s in stringCollection)
  2. {
  3.     string temp = s;
  4.     whereClause = whereClause.Or(p => p.SomeString == temp);
  5. }
Other than that, it works great.
May 12 '10 #1
Share this Article
Share on Google+