1. 程式人生 > >動態拼接lambda

動態拼接lambda

PredicateBuilder的UML類圖
  public static class PredicateBuilder
    {
        public static Expression<Func<T, bool>> True<T>() { return f => true; }
        public static Expression<Func<T, bool>> False<T>() { return f => false; }
        public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); 
            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>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.Or);
        }
    }
    public 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);
        }
    } 

測試程式碼:

   var condition = PredicateBuilder.True<policy>();
                condition=condition.And(p=>p.PolicyId==policyId);
                if (!string.IsNullOrEmpty(kindName))
                {
                    condition = condition.And(p => p.KindName.Contains(kindName) || p.KindName.StartsWith(kindName));
                }
                if (!string.IsNullOrEmpty(provisionName))
                {
                    condition = condition.And(p => p.ProvisionName.Contains(provisionName) || p.ProvisionName.StartsWith(provisionName));
                }
                if (itemKindNo > 0)
                {
                    condition = condition.And(p => p.ItemKindNo == itemKindNo);
                }
                var totalCount = _policyDetailRepository.GetList(condition).Count();
                var data= _policyDetailRepository.GetList(condition).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();