Created
April 13, 2020 20:21
-
-
Save Eonasdan/16c0a12a8c972633f9b33c3c3d13c825 to your computer and use it in GitHub Desktop.
Predicate Extensions
This file contains hidden or 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.Diagnostics; | |
| using System.Linq.Expressions; | |
| namespace Extensions | |
| { | |
| [DebuggerStepThrough] | |
| public static class PredicateExtensions | |
| { | |
| /// <summary> | |
| /// Begin an expression chain | |
| /// </summary> | |
| /// <typeparam name="T"></typeparam> | |
| /// <param name="value">Default return value if the chain is ended early</param> | |
| /// <returns>A lambda expression stub</returns> | |
| public static Expression<Func<T, bool>> Begin<T>(bool value = false) | |
| { | |
| if (value) return parameter => true; //value cannot be used in place of true/false | |
| return parameter => false; | |
| } | |
| public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left, | |
| Expression<Func<T, bool>> right) | |
| { | |
| return CombineLambdas(left, right, ExpressionType.AndAlso); | |
| } | |
| public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right) | |
| { | |
| return CombineLambdas(left, right, ExpressionType.OrElse); | |
| } | |
| #region private | |
| //HEY IT SAYS PRIVATE! j/k | |
| private static Expression<Func<T, bool>> CombineLambdas<T>(this Expression<Func<T, bool>> left, | |
| Expression<Func<T, bool>> right, ExpressionType expressionType) | |
| { | |
| //Remove expressions created with Begin<T>() | |
| if (IsExpressionBodyConstant(left)) return right; | |
| var p = left.Parameters[0]; | |
| var visitor = new SubstituteParameterVisitor { Substitute = { [right.Parameters[0]] = p } }; | |
| Expression body = Expression.MakeBinary(expressionType, left.Body, visitor.Visit(right.Body)); | |
| return Expression.Lambda<Func<T, bool>>(body, p); | |
| } | |
| private static bool IsExpressionBodyConstant<T>(Expression<Func<T, bool>> left) | |
| { | |
| return left.Body.NodeType == ExpressionType.Constant; | |
| } | |
| internal class SubstituteParameterVisitor : ExpressionVisitor | |
| { | |
| public readonly Dictionary<Expression, Expression> Substitute = new Dictionary<Expression, Expression>(); | |
| protected override Expression VisitParameter(ParameterExpression node) | |
| { | |
| return Substitute.TryGetValue(node, out var newValue) ? newValue : node; | |
| } | |
| } | |
| #endregion | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment