using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace HighWayIot.Common { /// /// 谓词表达式构建器 /// public static class ExpressionExtensions { /// /// 创建一个值恒为 true 的表达式。 /// /// 表达式方法类型 /// 一个值恒为 true 的表达式。 public static Expression> True() { return p => true; } /// /// 创建一个值恒为 false 的表达式。 /// /// 表达式方法类型 /// 一个值恒为 false 的表达式。 public static Expression> False() { return f => false; } /// /// 使用 Expression.OrElse 的方式拼接两个 System.Linq.Expression。 /// /// 表达式方法类型 /// 左边的 System.Linq.Expression 。 /// 右边的 System.Linq.Expression。 /// 拼接完成的 System.Linq.Expression。 public static Expression Or(this Expression left, Expression right) { return MakeBinary(left, right, Expression.OrElse); } /// /// 使用 Expression.AndAlso 的方式拼接两个 System.Linq.Expression。 /// /// 表达式方法类型 /// 左边的 System.Linq.Expression 。 /// 右边的 System.Linq.Expression。 /// 拼接完成的 System.Linq.Expression。 public static Expression And(this Expression left, Expression right) { return MakeBinary(left, right, Expression.AndAlso); } /// /// 使用自定义的方式拼接两个 System.Linq.Expression。 /// /// 表达式方法类型 /// 左边的 System.Linq.Expression 。 /// 右边的 System.Linq.Expression。 /// /// 拼接完成的 System.Linq.Expression。 private static Expression MakeBinary(this Expression left, Expression right, Func func) { return MakeBinary((LambdaExpression)left, right, func) as Expression; } /// /// 拼接两个 /// System.Linq.Expression /// ,两个 /// System.Linq.Expression /// 的参数必须完全相同。 /// /// 左边的 /// System.Linq.Expression /// /// 右边的 /// System.Linq.Expression /// /// 表达式拼接的具体逻辑 /// 拼接完成的 /// System.Linq.Expression /// private static LambdaExpression MakeBinary(this LambdaExpression left, LambdaExpression right, Func func) { var data = Combinate(right.Parameters, left.Parameters).ToArray(); right = ParameterReplace.Replace(right, data) as LambdaExpression; return Expression.Lambda(func(left.Body, right.Body), left.Parameters.ToArray()); } /// /// 合并参数 /// /// /// /// /// private static IEnumerable> Combinate(IEnumerable left, IEnumerable right) { var a = left.GetEnumerator(); var b = right.GetEnumerator(); while (a.MoveNext() && b.MoveNext()) yield return new KeyValuePair(a.Current, b.Current); } } internal sealed class ParameterReplace : ExpressionVisitor { public static Expression Replace(Expression e, IEnumerable> paramList) { var item = new ParameterReplace(paramList); return item.Visit(e); } private readonly Dictionary _parameters; public ParameterReplace(IEnumerable> paramList) { _parameters = paramList.ToDictionary(p => p.Key, p => p.Value, new ParameterEquality()); } protected override Expression VisitParameter(ParameterExpression p) { ParameterExpression result; if (_parameters.TryGetValue(p, out result)) return result; return base.VisitParameter(p); } #region class: ParameterEquality private class ParameterEquality : IEqualityComparer { public bool Equals(ParameterExpression x, ParameterExpression y) { if (x == null || y == null) return false; return x.Type == y.Type; } public int GetHashCode(ParameterExpression obj) { if (obj == null) return 0; return obj.Type.GetHashCode(); } } #endregion } }