Created
June 3, 2015 20:15
-
-
Save kcuzner/04826afa4275a429c00d to your computer and use it in GitHub Desktop.
Extensions for concatenation of existing expressions using AndAlso and OrElse into a new expression
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace ETP | |
{ | |
/// <summary> | |
/// Expression extension adapted from http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx | |
/// </summary> | |
static class ExpressionExtensions | |
{ | |
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) | |
{ | |
// build parameter map (from parameters of second to parameters of first) | |
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f); | |
// replace parameters in the second lambda expression with parameters from the first | |
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); | |
// apply composition of lambda expression bodies to parameters from the first expression | |
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters); | |
} | |
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) | |
{ | |
return first.Compose(second, Expression.And); | |
} | |
public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) | |
{ | |
return first.Compose(second, Expression.AndAlso); | |
} | |
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) | |
{ | |
return first.Compose(second, Expression.Or); | |
} | |
public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) | |
{ | |
return first.Compose(second, Expression.OrElse); | |
} | |
class ParameterRebinder : ExpressionVisitor | |
{ | |
private readonly Dictionary<ParameterExpression, ParameterExpression> map; | |
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) | |
{ | |
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); | |
} | |
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) | |
{ | |
return new ParameterRebinder(map).Visit(exp); | |
} | |
protected override Expression VisitParameter(ParameterExpression p) | |
{ | |
ParameterExpression replacement; | |
if (map.TryGetValue(p, out replacement)) | |
{ | |
p = replacement; | |
} | |
return base.VisitParameter(p); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment