C # refactoring lambda expressions

I have several Expression<Func<User,bool>> expressions that share properties. For example,

 Expression<Func<User, bool>> e1 = (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != null; Expression<Func<User, bool>> e2 = (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != "A"; Expression<Func<User, bool>> e3 = (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != "B"; 

Is there an easy way to put u.IsActive && u.Group != "PROCESS" in a variable and use it in e1, e2 and e3? Edited: And I still want the same tree.

It seems I can do this by building an expression using Expression.Lambda<Func<User, bool>>(BinaryExpression.AndAlso( etc. But instead of simplifying my code, this made it difficult to read.

+6
c # lambda expression-trees
source share
4 answers

I believe that there is no pure way to do this for your business. You can use BinaryExpression as you mentioned. You can encapsulate calls to BinaryExpression and Expression.Lambda in a method and call a call instead (like PredicateBuilder.And ), but none of them are as clean as the current IMO syntax.

+3
source share

The problem with lambda expressions is that they are immutable, and you cannot easily replace lambda parameters. My original idea was to do something like this ( unfortunately, this will not work ):

 public static class ExpressionExtesions { public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> baseCondition, Expression<Func<T, bool>> additionalCondition) { var and = Expression.AndAlso(baseCondition.Body, additionalCondition.Body); return Expression.Lambda<Func<T, bool>>(and, baseCondition.Parameters); // additionalCondition.Body still uses its own parameters so this fails on Compile() } } 

and use in code:

 Expression<Func<User, bool>> e = usr => usr.IsActive && usr.Group != "PROCESS"; var e1 = e.And(u => u.Name != null); var e2 = e.And(u => u.Name != "A"); var e3 = e.And(u => u.Name != "B"); 

Possible Solution

You can try to use one of the projects aimed at implementing expression builders. I have not used any of them, but google provides many links, for example:

Another approach

If you use these expressions in LINQ to filter values, you can use a different approach (do not combine expressions, but combine filters):

 var activeUsers = allUsers.Where(usr => usr.IsActive && usr.Group != "PROCESS"); var usersAll = activeUsers.Where(u => u.Name != null); var usersNotA = activeUsers.Where(u => u.Name != "A"); var usersNotB = activeUsers.Where(u => u.Name != "B"); 
+3
source share

I don’t think there should be a better answer than the one you are using already. As Mehrdad mentions, you need to build a deeper tree using BinaryExpression, and I think this will be a step back in readability from your current code.

Depending on your use, you can save some lines of code using closure semantics and doing something like this:

 string name = null; Expression<Func<User, bool>> e = (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != name; var expr = e.Compile(); name = "A"; var result = expr.Invoke(u); //True (assume u.Name = "B") name = "B"; result = expr.Invoke(u); //False 

... but whether it depends on what you do with the compiled delegate. It may be completely useless to you, but worth mentioning just in case!

+2
source share
 var test = new Func<User, bool>(u=> u.IsActive && u.Group != "PROCESS"); Expression<Func<User, bool>> e1 = (User u) => test(u) && u.Name != null; Expression<Func<User, bool>> e2 = (User u) => test(u) && u.Name != "A"; Expression<Func<User, bool>> e3 = (User u) => test(u) && u.Name != "B"; 
+1
source share

All Articles