diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index ddd18378..28fdb213 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -110,13 +110,6 @@ 清空状态数据 - - - 根据 lambda 条件删除数据 - - - - 添加 @@ -211,15 +204,6 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - 动态Type,在使用 Repository<object> 后使用本方法,指定实体类型 diff --git a/FreeSql.Tests/FreeSql.Tests/Extensions/LambadaExpressionExtensionsTest.cs b/FreeSql.Tests/FreeSql.Tests/Extensions/LambadaExpressionExtensionsTest.cs index 4c6d8e38..099d4417 100644 --- a/FreeSql.Tests/FreeSql.Tests/Extensions/LambadaExpressionExtensionsTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Extensions/LambadaExpressionExtensionsTest.cs @@ -12,29 +12,36 @@ namespace FreeSql.Tests.Extensions public void And() { Expression> where = a => a.id == Guid.Empty; - Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000' AND a.\"num\" > 0)", g.sqlite.Select().Where(where.And(b => b.num > 0)).ToSql().Replace("\r\n", "")); Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.And(false, b => b.num > 0)).ToSql().Replace("\r\n", "")); Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000' AND a.\"num\" = 1 AND a.\"num\" = 2)", g.sqlite.Select().Where(where.And(b => b.num == 1).And(b => b.num == 2)).ToSql().Replace("\r\n", "")); Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.And(false, b => b.num == 1).And(false, c => c.num == 2)).ToSql().Replace("\r\n", "")); - } + where = null; + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"num\" > 0)", g.sqlite.Select().Where(where.And(b => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a", g.sqlite.Select().Where(where.And(false, b => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"num\" = 1 AND a.\"num\" = 2)", g.sqlite.Select().Where(where.And(b => b.num == 1).And(b => b.num == 2)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a", g.sqlite.Select().Where(where.And(false, b => b.num == 1).And(false, c => c.num == 2)).ToSql().Replace("\r\n", "")); + } [Fact] public void Or() { Expression> where = a => a.id == Guid.Empty; - Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE ((a.\"id\" = '00000000-0000-0000-0000-000000000000' OR a.\"num\" > 0))", g.sqlite.Select().Where(where.Or(b => b.num > 0)).ToSql().Replace("\r\n", "")); Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.Or(false, b => b.num > 0)).ToSql().Replace("\r\n", "")); Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (((a.\"id\" = '00000000-0000-0000-0000-000000000000' OR a.\"num\" = 1) OR a.\"num\" = 2))", g.sqlite.Select().Where(where.Or(b => b.num == 1).Or(b => b.num == 2)).ToSql().Replace("\r\n", "")); Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.Or(false, b => b.num == 1).Or(false, c => c.num == 2)).ToSql().Replace("\r\n", "")); - } + where = null; + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"num\" > 0)", g.sqlite.Select().Where(where.Or(b => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a", g.sqlite.Select().Where(where.Or(false, b => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE ((a.\"num\" = 1 OR a.\"num\" = 2))", g.sqlite.Select().Where(where.Or(b => b.num == 1).Or(b => b.num == 2)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a", g.sqlite.Select().Where(where.Or(false, b => b.num == 1).Or(false, c => c.num == 2)).ToSql().Replace("\r\n", "")); + } [Fact] public void Not() { Expression> where = a => a.id == Guid.Empty; - Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (not(a.\"id\" = '00000000-0000-0000-0000-000000000000'))", g.sqlite.Select().Where(where.Not()).ToSql().Replace("\r\n", "")); Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a WHERE (a.\"id\" = '00000000-0000-0000-0000-000000000000')", g.sqlite.Select().Where(where.Not(false)).ToSql().Replace("\r\n", "")); } @@ -45,5 +52,49 @@ namespace FreeSql.Tests.Extensions public int num { get; set; } } + class testExpAddOr2 + { + public Guid id { get; set; } + + public int num { get; set; } + } + + [Fact] + public void And2() + { + Expression> where = (a, b) => a.id == b.id; + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (a.\"id\" = b.\"id\" AND b.\"num\" > 0)", g.sqlite.Select().Where(where.And((a, b) => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (a.\"id\" = b.\"id\")", g.sqlite.Select().Where(where.And(false, (a, b) => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (a.\"id\" = b.\"id\" AND b.\"num\" = 1 AND b.\"num\" = 2)", g.sqlite.Select().Where(where.And((a, b) => b.num == 1).And((a, b) => b.num == 2)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (a.\"id\" = b.\"id\")", g.sqlite.Select().Where(where.And(false, (a, b) => b.num == 1).And(false, (a, c) => c.num == 2)).ToSql().Replace("\r\n", "")); + + where = null; + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (b.\"num\" > 0)", g.sqlite.Select().Where(where.And((a, b) => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b", g.sqlite.Select().Where(where.And(false, (a, b) => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (b.\"num\" = 1 AND b.\"num\" = 2)", g.sqlite.Select().Where(where.And((a, b) => b.num == 1).And((a, b) => b.num == 2)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b", g.sqlite.Select().Where(where.And(false, (a, b) => b.num == 1).And(false, (a, c) => c.num == 2)).ToSql().Replace("\r\n", "")); + } + [Fact] + public void Or2() + { + Expression> where = (a, b) => a.id == b.id; + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE ((a.\"id\" = b.\"id\" OR b.\"num\" > 0))", g.sqlite.Select().Where(where.Or((a, b) => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (a.\"id\" = b.\"id\")", g.sqlite.Select().Where(where.Or(false, (a, b) => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (((a.\"id\" = b.\"id\" OR b.\"num\" = 1) OR b.\"num\" = 2))", g.sqlite.Select().Where(where.Or((a, b) => b.num == 1).Or((a, b) => b.num == 2)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (a.\"id\" = b.\"id\")", g.sqlite.Select().Where(where.Or(false, (a, b) => b.num == 1).Or(false, (a, c) => c.num == 2)).ToSql().Replace("\r\n", "")); + + where = null; + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (b.\"num\" > 0)", g.sqlite.Select().Where(where.Or((a, b) => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b", g.sqlite.Select().Where(where.Or(false, (a, b) => b.num > 0)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE ((b.\"num\" = 1 OR b.\"num\" = 2))", g.sqlite.Select().Where(where.Or((a, b) => b.num == 1).Or((a, b) => b.num == 2)).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b", g.sqlite.Select().Where(where.Or(false, (a, b) => b.num == 1).Or(false, (a, c) => c.num == 2)).ToSql().Replace("\r\n", "")); + } + [Fact] + public void Not2() + { + Expression> where = (a, b) => a.id == b.id; + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (not(a.\"id\" = b.\"id\"))", g.sqlite.Select().Where(where.Not()).ToSql().Replace("\r\n", "")); + Assert.Equal("SELECT a.\"id\", a.\"num\" FROM \"testExpAddOr\" a, \"testExpAddOr2\" b WHERE (a.\"id\" = b.\"id\")", g.sqlite.Select().Where(where.Not(false)).ToSql().Replace("\r\n", "")); + } } } diff --git a/FreeSql/Extensions/LambadaExpressionExtensions.cs b/FreeSql/Extensions/LambadaExpressionExtensions.cs index 034efdd3..1b05dbf1 100644 --- a/FreeSql/Extensions/LambadaExpressionExtensions.cs +++ b/FreeSql/Extensions/LambadaExpressionExtensions.cs @@ -14,79 +14,219 @@ namespace System.Linq.Expressions public static partial class LambadaExpressionExtensions { - /// - /// 使用 and 拼接两个 lambda 表达式 - /// - /// - public static Expression> And(this Expression> exp1, Expression> exp2) => And(exp1, true, exp2); - /// - /// 使用 and 拼接两个 lambda 表达式 - /// - /// - /// - /// true 时生效 - /// - /// - public static Expression> And(this Expression> exp1, bool condition, Expression> exp2) + 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; - ParameterExpression newParameter = Expression.Parameter(typeof(T), "c"); - NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter, exp2.Parameters.FirstOrDefault()); + var newParameters = exp1.Parameters.Select((a, b) => Expression.Parameter(a.Type, $"new{b}")).ToArray(); - var left = visitor.Replace(exp1.Body); - var right = visitor.Replace(exp2.Body); - var body = Expression.AndAlso(left, right); - return Expression.Lambda>(body, newParameter); + var left = new NewExpressionVisitor(newParameters, exp2.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); } - - /// - /// 使用 or 拼接两个 lambda 表达式 - /// - /// - public static Expression> Or(this Expression> exp1, Expression> exp2) => Or(exp1, true, exp2); - /// - /// 使用 or 拼接两个 lambda 表达式 - /// - /// - /// - /// true 时生效 - /// - /// - public static Expression> Or(this Expression> exp1, bool condition, Expression> exp2) - { - if (condition == false) return exp1; - if (exp1 == null) return exp2; - if (exp2 == null) return exp1; - - ParameterExpression newParameter = Expression.Parameter(typeof(T), "c"); - NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter, exp2.Parameters.FirstOrDefault()); - - var left = visitor.Replace(exp1.Body); - var right = visitor.Replace(exp2.Body); - var body = Expression.OrElse(left, right); - return Expression.Lambda>(body, newParameter); - } - - /// - /// 将 lambda 表达式取反 - /// - /// - /// - /// true 时生效 - /// - public static Expression> Not(this Expression> exp, bool condition = true) + static LambdaExpression InternalNotExpression(bool condition, LambdaExpression exp) { if (condition == false) return exp; if (exp == null) return null; - var candidateExpr = exp.Parameters[0]; + var newParameters = exp.Parameters.Select((a, b) => Expression.Parameter(a.Type, $"new{b}")).ToArray(); var body = Expression.Not(exp.Body); - return Expression.Lambda>(body, candidateExpr); + return Expression.Lambda(exp.Type, body, newParameters); } + #region T1 + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + public static Expression> And(this Expression> exp1, Expression> exp2) => And(exp1, true, exp2); + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> And(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, true); + + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + public static Expression> Or(this Expression> exp1, Expression> exp2) => Or(exp1, true, exp2); + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> Or(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, false); + + /// + /// 将 lambda 表达式取反 + /// + /// + /// true 时生效 + /// + public static Expression> Not(this Expression> exp, bool condition = true) => (Expression>)InternalNotExpression(condition, exp); + #endregion + + #region T1, T2 + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + public static Expression> And(this Expression> exp1, Expression> exp2) => And(exp1, true, exp2); + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> And(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, true); + + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + public static Expression> Or(this Expression> exp1, Expression> exp2) => Or(exp1, true, exp2); + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> Or(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, false); + + /// + /// 将 lambda 表达式取反 + /// + /// + /// true 时生效 + /// + public static Expression> Not(this Expression> exp, bool condition = true) => (Expression>)InternalNotExpression(condition, exp); + #endregion + + #region T1, T2, T3 + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + public static Expression> And(this Expression> exp1, Expression> exp2) => And(exp1, true, exp2); + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> And(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, true); + + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + public static Expression> Or(this Expression> exp1, Expression> exp2) => Or(exp1, true, exp2); + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> Or(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, false); + + /// + /// 将 lambda 表达式取反 + /// + /// + /// true 时生效 + /// + public static Expression> Not(this Expression> exp, bool condition = true) => (Expression>)InternalNotExpression(condition, exp); + #endregion + + #region T1, T2, T3, T4 + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + public static Expression> And(this Expression> exp1, Expression> exp2) => And(exp1, true, exp2); + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> And(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, true); + + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + public static Expression> Or(this Expression> exp1, Expression> exp2) => Or(exp1, true, exp2); + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> Or(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, false); + + /// + /// 将 lambda 表达式取反 + /// + /// + /// true 时生效 + /// + public static Expression> Not(this Expression> exp, bool condition = true) => (Expression>)InternalNotExpression(condition, exp); + #endregion + + #region T1, T2, T3, T4, T5 + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + public static Expression> And(this Expression> exp1, Expression> exp2) => And(exp1, true, exp2); + /// + /// 使用 and 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> And(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, true); + + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + public static Expression> Or(this Expression> exp1, Expression> exp2) => Or(exp1, true, exp2); + /// + /// 使用 or 拼接两个 lambda 表达式 + /// + /// + /// true 时生效 + /// + /// + public static Expression> Or(this Expression> exp1, bool condition, Expression> exp2) => (Expression>)InternalAndOrExpression(condition, exp1, exp2, false); + + /// + /// 将 lambda 表达式取反 + /// + /// + /// true 时生效 + /// + public static Expression> Not(this Expression> exp, bool condition = true) => (Expression>)InternalNotExpression(condition, exp); + #endregion + internal static bool IsParameter(this Expression exp) { var test = new TestParameterExpressionVisitor(); @@ -97,17 +237,23 @@ namespace System.Linq.Expressions internal class NewExpressionVisitor : ExpressionVisitor { - ParameterExpression _newParameter; - ParameterExpression _oldParameter; - public NewExpressionVisitor(ParameterExpression newParam, ParameterExpression oldParam) + ParameterExpression[] _newParameters; + ParameterExpression[] _oldParameters; + public NewExpressionVisitor(ParameterExpression newParam, ParameterExpression oldParam) : this(new[] { newParam }, new[] { oldParam }) { } + public NewExpressionVisitor(ParameterExpression[] newParams, ParameterExpression[] oldParams) { - this._newParameter = newParam; - this._oldParameter = oldParam; + this._newParameters = newParams; + this._oldParameters = oldParams; } public Expression Replace(Expression exp) => this.Visit(exp); - protected override Expression VisitParameter(ParameterExpression node) => - node == _oldParameter ? this._newParameter : node; + protected override Expression VisitParameter(ParameterExpression node) + { + for (var a = 0; a < _oldParameters.Length; a++) + if (_oldParameters[a] == node) + return _newParameters[a]; + return node; + } } internal class TestParameterExpressionVisitor : ExpressionVisitor diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 1c0d9a4a..cd174404 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -3319,7 +3319,6 @@ 使用 and 拼接两个 lambda 表达式 - true 时生效 @@ -3335,7 +3334,6 @@ 使用 or 拼接两个 lambda 表达式 - true 时生效 @@ -3345,7 +3343,158 @@ 将 lambda 表达式取反 - + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + + + true 时生效 + + + + + 使用 and 拼接两个 lambda 表达式 + + + + + + 使用 and 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + + + + 使用 or 拼接两个 lambda 表达式 + + + true 时生效 + + + + + + 将 lambda 表达式取反 + true 时生效