在FreeSql源码中Expression表达式拼接默认最多支持到5个泛型参数,当我们使用表关联比较多的时候,就需要进行扩展。
新建一个类,将命名空间改为System.Linq.Expressions,并加入参数扩展
namespace System.Linq.Expressions { static partial class LambadaExpressionExtensions { //如需扩展增加泛型参数即可 #region T1, T2, T3, T4, T5 ,T6 /// <summary> /// 使用 and 拼接两个 lambda 表达式 /// </summary> /// <returns></returns> public static Expression<Func<T1, T2, T3, T4, T5, T6, bool>> And<T1, T2, T3, T4, T5, T6>(this Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp1, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp2) => And(exp1, true, exp2); /// <summary> /// 使用 and 拼接两个 lambda 表达式 /// </summary> /// <param name="exp1"></param> /// <param name="condition">true 时生效</param> /// <param name="exp2"></param> /// <returns></returns> public static Expression<Func<T1, T2, T3, T4, T5, T6, bool>> And<T1, T2, T3, T4, T5, T6>(this Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp1, bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp2) => (Expression<Func<T1, T2, T3, T4, T5, T6, bool>>)InternalAndOrExpression(condition, exp1, exp2, true); /// <summary> /// 使用 or 拼接两个 lambda 表达式 /// </summary> /// <returns></returns> public static Expression<Func<T1, T2, T3, T4, T5, T6, bool>> Or<T1, T2, T3, T4, T5, T6>(this Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp1, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp2) => Or(exp1, true, exp2); /// <summary> /// 使用 or 拼接两个 lambda 表达式 /// </summary> /// <param name="exp1"></param> /// <param name="condition">true 时生效</param> /// <param name="exp2"></param> /// <returns></returns> public static Expression<Func<T1, T2, T3, T4, T5, T6, bool>> Or<T1, T2, T3, T4, T5, T6>(this Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp1, bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp2) => (Expression<Func<T1, T2, T3, T4, T5, T6, bool>>)InternalAndOrExpression(condition, exp1, exp2, false); /// <summary> /// 将 lambda 表达式取反 /// </summary> /// <param name="exp"></param> /// <param name="condition">true 时生效</param> /// <returns></returns> public static Expression<Func<T1, T2, T3, T4, T5, T6, bool>> Not<T1, T2, T3, T4, T5, T6>(this Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp, bool condition = true) => (Expression<Func<T1, T2, T3, T4, T5, T6, bool>>)InternalNotExpression(condition, exp); #endregion #region 通用表达式方法 static LambdaExpression InternalAndOrExpression(bool condition, LambdaExpression exp1, LambdaExpression exp2, bool isAndAlso) { if (condition == false) return exp1; if (exp1 == null) return exp2; if (exp2 == null) return exp1; var newParameters = exp1.Parameters.Select((a, b) => Expression.Parameter(a.Type, a.Name /*$"new{b}"*/)).ToArray(); var left = new NewExpressionVisitor(newParameters, exp1.Parameters.ToArray()).Replace(exp1.Body); var right = new NewExpressionVisitor(newParameters, exp2.Parameters.ToArray()).Replace(exp2.Body); var body = isAndAlso ? Expression.AndAlso(left, right) : Expression.OrElse(left, right); return Expression.Lambda(exp1.Type, body, newParameters); } static LambdaExpression InternalNotExpression(bool condition, LambdaExpression exp) { if (condition == false) return exp; if (exp == null) return null; var newParameters = exp.Parameters.Select((a, b) => Expression.Parameter(a.Type, a.Name /*$"new{b}"*/)).ToArray(); var body = Expression.Not(exp.Body); return Expression.Lambda(exp.Type, body, newParameters); } internal class NewExpressionVisitor : ExpressionVisitor { ParameterExpression[] _newParameters; ParameterExpression[] _oldParameters; public NewExpressionVisitor(ParameterExpression newParam, ParameterExpression oldParam) : this(new[] { newParam }, new[] { oldParam }) { } public NewExpressionVisitor(ParameterExpression[] newParams, ParameterExpression[] oldParams) { this._newParameters = newParams; this._oldParameters = oldParams; } public Expression Replace(Expression exp) => this.Visit(exp); protected override Expression VisitParameter(ParameterExpression node) { for (var a = 0; a < _oldParameters.Length; a++) if (_oldParameters[a] == node) return _newParameters[a]; return node; } } #endregion } }
以上代码是将表达式拼接扩展至6个泛型参数,以此类推。
因为属于同一个命名空间,可以直接使用。