PredicateExtensions.cs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq.Expressions;
  4. namespace InABox.Core
  5. {
  6. public static class PredicateExtensions
  7. {
  8. /// <summary>
  9. /// Begin an expression chain
  10. /// </summary>
  11. /// <typeparam name="T"></typeparam>
  12. /// <param name="value">Default return value if the chanin is ended early</param>
  13. /// <returns>A lambda expression stub</returns>
  14. public static Expression<Func<T, bool>> Begin<T>(bool value = false)
  15. {
  16. if (value)
  17. return parameter => true; //value cannot be used in place of true/false
  18. return parameter => false;
  19. }
  20. public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left,
  21. Expression<Func<T, bool>> right)
  22. {
  23. return CombineLambdas(left, right, ExpressionType.AndAlso);
  24. }
  25. public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
  26. {
  27. return CombineLambdas(left, right, ExpressionType.OrElse);
  28. }
  29. #region private
  30. private static Expression<Func<T, R>> CombineLambdas<T, R>(this Expression<Func<T, R>> left,
  31. Expression<Func<T, R>> right, ExpressionType expressionType)
  32. {
  33. //Remove expressions created with Begin<T>()
  34. if (IsExpressionBodyConstant(left))
  35. return right;
  36. var p = left.Parameters[0];
  37. var visitor = new SubstituteParameterVisitor();
  38. visitor.Sub[right.Parameters[0]] = p;
  39. Expression body = Expression.MakeBinary(expressionType, left.Body, visitor.Visit(right.Body));
  40. return Expression.Lambda<Func<T, R>>(body, p);
  41. }
  42. private static bool IsExpressionBodyConstant<T, R>(Expression<Func<T, R>> left)
  43. {
  44. return left.Body.NodeType == ExpressionType.Constant;
  45. }
  46. internal class SubstituteParameterVisitor : ExpressionVisitor
  47. {
  48. public Dictionary<Expression, Expression> Sub = new Dictionary<Expression, Expression>();
  49. protected override Expression VisitParameter(ParameterExpression node)
  50. {
  51. Expression newValue;
  52. if (Sub.TryGetValue(node, out newValue)) return newValue;
  53. return node;
  54. }
  55. }
  56. #endregion
  57. }
  58. }