using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using VCommon.Collections; using static System.Linq.Expressions.Expression; namespace VCommon.Linq.Expressions.Predicate { public sealed class PredicateBuilder { public static readonly PredicateBuilder Instance = new PredicateBuilder(); private PredicateBuilder() { } public PredicateWrap Custom(Expression> expression) => expression; public PredicateWrap In(Expression> selector, IEnumerable checkIn) { if (checkIn == null) return null; var c = Constant(checkIn.WrapEnumerable()); var p = selector.Parameters[0]; var call = Call(typeof(Enumerable), "Contains", new[] { typeof(TV) }, c, selector.Body); var exp = Lambda>(call, p); return exp; } public PredicateWrap NotIn(Expression> selector, IEnumerable checkIn) { if (checkIn == null) return null; var p = selector.Parameters[0]; var values = Constant(checkIn.WrapEnumerable()); var @in = Call(typeof(Enumerable), "Contains", new[] { typeof(TV) }, values, selector.Body); var not = Not(@in); var exp = Lambda>(not, p); return exp; } public PredicateWrap StringContains(Expression> selector, string contains) { if (string.IsNullOrWhiteSpace(contains)) return null; var stringContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }) ?? throw new SystemException("ILL SYSTEM LIB? string.Contains(string) NOT EXIST??"); var parameterExp = selector.Parameters[0]; var valExp = Constant(contains, typeof(string)); var callExp = Call(selector.Body, stringContainsMethod, valExp); var lambda = Lambda>(callExp, parameterExp); return lambda; } public PredicateWrap Between(Expression> selector, TV min, TV max, bool include = true) { if (null == min && null == max) return null; PredicateWrap predicateWrap = null; if (null != min) { predicateWrap = include ? GreaterThanOrEqual(selector, min) : GreaterThan(selector, min); } if (null != max) { predicateWrap &= include ? LessThanOrEqual(selector, max) : LessThan(selector, max); } return predicateWrap; } public PredicateWrap Equal(Expression> selector, TV valueToCompare) => BinOp(Expression.Equal, selector, valueToCompare); public PredicateWrap NotEqual(Expression> selector, TV valueToCompare) => BinOp(Expression.NotEqual, selector, valueToCompare); public PredicateWrap LessThan(Expression> selector, TV valueToCompare) => BinOp(Expression.LessThan, selector, valueToCompare); public PredicateWrap LessThanOrEqual(Expression> selector, TV valueToCompare) => BinOp(Expression.LessThanOrEqual, selector, valueToCompare); public PredicateWrap GreaterThan(Expression> selector, TV valueToCompare) => BinOp(Expression.GreaterThan, selector, valueToCompare); public PredicateWrap GreaterThanOrEqual(Expression> selector, TV valueToCompare) => BinOp(Expression.GreaterThanOrEqual, selector, valueToCompare); private static PredicateWrap BinOp(Func op, Expression> selector, TV valueToCompare) { var parameterExp = selector.Parameters[0]; var valToCompareExp = Constant(valueToCompare, typeof(TV)); var callExp = op(selector.Body, valToCompareExp); var lambda = Lambda>(callExp, parameterExp); return lambda; } } }