Combine Lambda Expressions: The And and the Or
- Sean
Found this post here but wanted to make a really simple example to demonstrate this.
The idea is simple, take something like this:
currentItem => currentItem.BooleanMethodOne() && currentItem.BooleanMethodTwo()
but say you only want to have one clause or both. Well you could make three separate expressions, but what if you wanted to add even more later? What if you wanted to mix and match? What if you're reading thing because you watched to see what page could possibly be on the last page of a google search? Well I have answers... stolen answers.
First the needed And and Or methods:
public static Expression<Func<T, Boolean>> And<T>( Expression<Func<T, Boolean>> expressionOne, Expression<Func<T, Boolean>> expressionTwo ) { //Basically this is like a bridge between the two expressions. It will take the T //parameter from expressionOne and apply it to expression two. So if // oneItem => oneItem.OneMethod() is expressionOne // twoItem => twoItem.TwoMethod() is expressionTwo //it would be like replacing the twoItem with the oneItem so that they now point //to the same thing. var invokedSecond = Expression.Invoke(expressionTwo, expressionOne.Parameters.Cast<Expression>()); //Now this is to create the needed expresions to return. It will take both early expressions //and use the item from the first expression in both. //It will look something like this: //currentItem => (currentItem.OneMethod And Invoke(currentItem => currentItem.TwoMethod())) //As you can see, it looks to be running expressionOne and then a new method that basically //calls expressionTwo with the same value (currentItem) return Expression.Lambda<Func<T, Boolean>>( Expression.And(expressionOne.Body, invokedSecond), expressionOne.Parameters ); } public static Expression<Func<T, Boolean>> Or<T>( Expression<Func<T, Boolean>> expressionOne, Expression<Func<T, Boolean>> expressionTwo ) { var invokedSecond = Expression.Invoke(expressionTwo, expressionOne.Parameters.Cast<Expression>()); return Expression.Lambda<Func<T, Boolean>>( Expression.Or(expressionOne.Body, invokedSecond), expressionOne.Parameters ); }
And here's a test for it:
String[] list; list = new String[] { "a", "b", "c", "ac", "ab", "cc", "d", "dd", "dc" }; Expression<Func<String, Boolean>> stringLikeA = currentString => currentString.Contains("a"); Expression<Func<String, Boolean>> stringLikeB = currentString => currentString.Contains("b"); Expression<Func<String, Boolean>> stringLikeC = currentString => currentString.Contains("c"); Expression<Func<String, Boolean>> neededUser = And<String>(stringLikeA, stringLikeB); list.Where(neededUser.Compile()); //a Assert.IsTrue(list.Where(neededUser.Compile()).Count() == 1); //ab //a, c, ac, ab, cc, dc neededUser = Or<String>(stringLikeA, stringLikeC); Assert.IsTrue(list.Where(neededUser.Compile()).Count() == 6); //ab, c, ac, cc, dc neededUser = And<String>(stringLikeA, stringLikeB); neededUser = Or<String>(neededUser, stringLikeC); Assert.IsTrue(list.Where(neededUser.Compile()).Count() == 5);
USINGS!!ONEONE
using System; using System.Linq; using System.Linq.Expressions; using Microsoft.VisualStudio.TestTools.UnitTesting;
I’m starting to worry about myself
- Sean
So the "dynamic" linq query so far isn't just enough to stop. Oh no, now that I can have methods pass back expressions, what about a dictionary of order by expressions to allow an even more dynamic feel? Huh? How's about that kids? I hate myself too.
//Enum created for the dictionary key public enum OrderByChoice { FirstName, LastName, UserName } //dictionary of expressions private static Dictionary<OrderByChoice, Expression<Func<User, String>>> GetOrderByList() { if(orderByList == null) { orderByList = new Dictionary<OrderByChoice,Expression<Func<User, String>>>(); orderByList.Add(OrderByChoice.FirstName, currentUser => currentUser.FirstName); orderByList.Add(OrderByChoice.LastName, currentUser => currentUser.LastName); orderByList.Add(OrderByChoice.UserName, currentUser => currentUser.UserName); } return orderByList; }
That's right, I know. Silly, but I think it's cool. Now mind you, I could have methods that return expressions instead of the expressions themselves, but I wanted to show the expressions.
And for the method call:
public static IList<User> GetUserList(OrderByChoice orderBy) { return GetUserList(currentUser => true, GetOrderByList()[orderBy]).ToList(); }
And now you have an even more dynamicish call.
I FORGOT THE USINGS!!!!
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions;

