1. 温习访问者模式,简单的说就是,按照既定的路线去一步一步访问,在访问中间步骤做点其他扩展!
    2. expression应用: ```csharp //为什么要使用表达式目录树来拼装解析呢; //可以提高重用性; //如果封装好一个方法,接受一个表达式目录树,在解析的时候,其实就是不断的访问,访问有规则; //任何一个表达式目录树我都可以调用当前方法来解析; //表达式目录树可以支持泛型;封装的时候个人认为好封装一些;

      //应用1:把表达式拼装成sql {

      1. Expression<Func<People, bool>> lambda = x => x.Age > 5 && x.Id > 5
      2. && x.Name.StartsWith("1") // like '1%'
      3. && x.Name.EndsWith("1") // like '%1'
      4. && x.Name.Contains("1");// like '%1%'
    1. ConditionBuilderVisitor vistor = new ConditionBuilderVisitor();
    2. vistor.Visit(lambda);
    3. Console.WriteLine(vistor.Condition());
    4. }
    5. /// <summary>
    6. /// 表达式树转化成Sql,首先继承 ExpressionVisitor,该类的Visit方法就是自动识别该表达式的形式,分配给适合的方法做解析
    7. /// </summary>
    8. public class ConditionBuilderVisitor : ExpressionVisitor
    9. {
    10. private Stack<string> _StringStack = new Stack<string>();
    11. public string Condition()
    12. {
    13. string condition = string.Concat(this._StringStack.ToArray());
    14. this._StringStack.Clear();
    15. return condition;
    16. }
    17. /// <summary>
    18. /// 如果是二元表达式
    19. /// </summary>
    20. /// <param name="node"></param>
    21. /// <returns></returns>
    22. protected override Expression VisitBinary(BinaryExpression node)
    23. {
    24. if (node == null) throw new ArgumentNullException("BinaryExpression");
    25. this._StringStack.Push(")");
    26. base.Visit(node.Right);//解析右边
    27. this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " ");
    28. base.Visit(node.Left);//解析左边
    29. this._StringStack.Push("(");
    30. return node;
    31. }
    32. /// <summary>
    33. /// 解析属性
    34. /// </summary>
    35. /// <param name="node"></param>
    36. /// <returns></returns>
    37. protected override Expression VisitMember(MemberExpression node)
    38. {
    39. if (node == null) throw new ArgumentNullException("MemberExpression");
    40. //this._StringStack.Push(" [" + node.Member.Name + "] ");
    41. ////return node;
    42. if (node.Expression is ConstantExpression)
    43. {
    44. var value1 = this.InvokeValue(node);
    45. var value2 = this.ReflectionValue(node);
    46. //this.ConditionStack.Push($"'{value1}'");
    47. this._StringStack.Push("'" + value2 + "'");
    48. }
    49. else
    50. {
    51. this._StringStack.Push(" [" + node.Member.Name + "] ");
    52. }
    53. return node;
    54. }
    55. private object InvokeValue(MemberExpression member)
    56. {
    57. var objExp = Expression.Convert(member, typeof(object));//struct需要
    58. return Expression.Lambda<Func<object>>(objExp).Compile().Invoke();
    59. }
    60. private object ReflectionValue(MemberExpression member)
    61. {
    62. var obj = (member.Expression as ConstantExpression).Value;
    63. return (member.Member as FieldInfo).GetValue(obj);
    64. }
    65. /// <summary>
    66. /// 常量表达式
    67. /// </summary>
    68. /// <param name="node"></param>
    69. /// <returns></returns>
    70. protected override Expression VisitConstant(ConstantExpression node)
    71. {
    72. if (node == null) throw new ArgumentNullException("ConstantExpression");
    73. this._StringStack.Push(" '" + node.Value + "' ");
    74. return node;
    75. }
    76. /// <summary>
    77. /// 方法表达式
    78. /// </summary>
    79. /// <param name="m"></param>
    80. /// <returns></returns>
    81. protected override Expression VisitMethodCall(MethodCallExpression m)
    82. {
    83. if (m == null) throw new ArgumentNullException("MethodCallExpression");
    84. string format;
    85. switch (m.Method.Name)
    86. {
    87. case "StartsWith":
    88. format = "({0} LIKE {1}+'%')";
    89. break;
    90. case "Contains":
    91. format = "({0} LIKE '%'+{1}+'%')";
    92. break;
    93. case "EndsWith":
    94. format = "({0} LIKE '%'+{1})";
    95. break;
    96. default:
    97. throw new NotSupportedException(m.NodeType + " is not supported!");
    98. }
    99. this.Visit(m.Object);
    100. this.Visit(m.Arguments[0]);
    101. string right = this._StringStack.Pop();
    102. string left = this._StringStack.Pop();
    103. this._StringStack.Push(String.Format(format, left, right));
    104. return m;
    105. }
    106. }
    1. ```csharp
    2. 先插入一个场景:根据条件搜索
    3. {
    4. //现在是Linq to SQL
    5. var dbSet = new List<People>().AsQueryable();//EF DbSet
    6. dbSet.Where(p => p.Age == 25 & p.Name.Contains("李四"));
    7. Expression<Func<People, bool>> exp = null;
    8. Console.WriteLine("用户输入个名称,为空就跳过");
    9. string name = Console.ReadLine();
    10. if (!string.IsNullOrWhiteSpace(name))
    11. {
    12. exp = p => p.Name.Contains(name);
    13. }
    14. Console.WriteLine("用户输入个最小年纪,为空就跳过");
    15. string age = Console.ReadLine();
    16. if (!string.IsNullOrWhiteSpace(age) && int.TryParse(age, out int iAge))
    17. {
    18. exp = p => p.Age > iAge;
    19. }
    20. }
    21. }
    22. //提问:
    23. //上面的玩法是不是只有最后一个条件才生效?
    24. //如果需要两个条件都满足呢? 怎么解决,可以做到表达式目录树的合并(且) 或 非
    25. //解答:
    26. 当然是拼装啊;拼装可以从最小粒度来组装表达式目录树~~
    27. 如果有一个封装,你把各种条件给我,我从最小粒度开始一个一个的拼装起来,不就是一个长的表达式目录树了吗?
    1. //应用2: 表达式链接
    2. Expression<Func<People, bool>> lambda1 = x => x.Age > 5;
    3. Expression<Func<People, bool>> lambda2 = x => x.Id > 5;
    4. //现有表达式数lambda1,lambda2如何有目的把他们连接起来
    5. //Expression<Func<People, bool>> newExpress = x => x.Age > 5 && x.Id > 5;
    6. Expression<Func<People, bool>> lambda3 = lambda1.And(lambda2); //且
    7. Expression<Func<People, bool>> lambda4 = lambda1.Or(lambda2);//或
    8. Expression<Func<People, bool>> lambda5 = lambda1.Not();//非
    9. Do1(lambda3);
    10. Do1(lambda4);
    11. Do1(lambda5);
    12. //验证方法
    13. private static void Do1(Expression<Func<People, bool>> func)
    14. {
    15. List<People> people = new List<People>()
    16. {
    17. new People(){Id=4,Name="123",Age=4},
    18. new People(){Id=5,Name="234",Age=5},
    19. new People(){Id=6,Name="345",Age=6},
    20. };
    21. List<People> peopleList = people.Where(func.Compile()).ToList();
    22. }
    23. /// <summary>
    24. /// 合并表达式 And Or Not扩展
    25. /// </summary>
    26. public static class ExpressionExtend
    27. {
    28. /// <summary>
    29. /// 合并表达式 expr1 AND expr2
    30. /// </summary>
    31. /// <typeparam name="T"></typeparam>
    32. /// <param name="expr1"></param>
    33. /// <param name="expr2"></param>
    34. /// <returns></returns>
    35. public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    36. {
    37. //return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, expr2.Body), expr1.Parameters);
    38. ParameterExpression newParameter = Expression.Parameter(typeof(T), "c");
    39. NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
    40. var left = visitor.Replace(expr1.Body);
    41. var right = visitor.Replace(expr2.Body); //为了能够生成一个新的表达式目录树
    42. var body = Expression.And(left, right);
    43. return Expression.Lambda<Func<T, bool>>(body, newParameter);
    44. }
    45. /// <summary>
    46. /// 合并表达式 expr1 or expr2
    47. /// </summary>
    48. /// <typeparam name="T"></typeparam>
    49. /// <param name="expr1"></param>
    50. /// <param name="expr2"></param>
    51. /// <returns></returns>
    52. public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    53. {
    54. ParameterExpression newParameter = Expression.Parameter(typeof(T), "c");
    55. NewExpressionVisitor visitor = new NewExpressionVisitor(newParameter);
    56. var left = visitor.Replace(expr1.Body);
    57. var right = visitor.Replace(expr2.Body);
    58. var body = Expression.Or(left, right);
    59. return Expression.Lambda<Func<T, bool>>(body, newParameter);
    60. }
    61. public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr)
    62. {
    63. var candidateExpr = expr.Parameters[0];
    64. var body = Expression.Not(expr.Body);
    65. return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
    66. }
    67. }
    68. /// <summary>
    69. /// 建立新表达式
    70. /// </summary>
    71. internal class NewExpressionVisitor : ExpressionVisitor
    72. {
    73. public ParameterExpression _NewParameter { get; private set; }
    74. public NewExpressionVisitor(ParameterExpression param)
    75. {
    76. this._NewParameter = param;
    77. }
    78. public Expression Replace(Expression exp)
    79. {
    80. return this.Visit(exp);
    81. }
    82. protected override Expression VisitParameter(ParameterExpression node)
    83. {
    84. return this._NewParameter;
    85. }
    86. }