2.1 委托的使用

能够解耦&代码重用

  1. public void SayHi(string name,SayHiDelegate method){
  2. //公共方法.....
  3. method.Invoke(name);
  4. //公共方法....
  5. }

多波委托拆解后的异步调用

  1. public delegate void TestFun();
  2. static void Main(string[] args) {
  3. //多播委托
  4. TestFun testFun = new TestFun(() => Console.WriteLine("Hello World"));
  5. testFun += new TestFun(() => Console.WriteLine("Hello World"));
  6. testFun+= new TestFun(() => Console.WriteLine("Hello World"));
  7. testFun.Invoke();
  8. //多播委托无法进行异步调用,可通过此方法进行拆解
  9. foreach (TestFun item in testFun.GetInvocationList()) {
  10. item.BeginInvoke(null,null);
  11. }
  12. }
  13. }

2.2 Lambda

参数列表=>方法体,Lambda表达式就是一个匿名方法,就是一个方法。
基于lambda表达式注册的多播委托是无法移除的。

2.2.1 发展过程

  1. public void delegate SayHiDelegate(string name);
  2. public void SayHi(string name){
  3. Console.WriteLine($"Say Hi,{name}");
  4. }
  5. //.NET Framework1.0
  6. SayHiDelegate sayHi = new SayHiDelegate(this.SayHi);
  7. sayHi.Invoke("Albert");
  8. //.NET Framework2.0 匿名方法
  9. SayHiDelegate sayHi = new SayHiDelegate(delegate (string name){
  10. Console.WriteLine($"Say Hi,{name}");
  11. });
  12. sayHi.Invoke("Albert");
  13. //.NET Framework3.0 delegate变为=>
  14. //lambda参数类型可以推断出来,可省略。根据委托的约束来推断出的。 语法糖
  15. SayHiDelegate sayHi = new SayHiDelegate(name =>{
  16. Console.WriteLine($"Say Hi,{name}");
  17. });
  18. sayHi.Invoke("Albert");
  19. //如果方法体只有一行,可以省略大括号+分号 语法糖
  20. SayHiDelegate sayHi = new SayHiDelegate(name =>
  21. Console.WriteLine($"Say Hi,{name}")
  22. );
  23. sayHi.Invoke("Albert");
  24. //实例化委托时,可以省略new SayHiDelegate 语法糖
  25. SayHiDelegate sayHi = name =>
  26. Console.WriteLine($"Say Hi,{name}");
  27. sayHi.Invoke("Albert");

2.2.2 对Lambda用于表达式目录树进行解析

解析类
ConditionBuilderVistor.cs ConditionBuilderVisitor.cs
SqlOperator.csSqlOperator.cs

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace MyDelegateEvent.ExpressionTest
  8. {
  9. public class ConditionBuilderVisitor : ExpressionVisitor
  10. {
  11. private Stack<string> _StringStack = new Stack<string>();
  12. public string Condition()
  13. {
  14. string condition = string.Concat(this._StringStack.ToArray());
  15. this._StringStack.Clear();
  16. return condition;
  17. }
  18. /// <summary>
  19. /// 二元表达式
  20. /// </summary>
  21. /// <param name="node"></param>
  22. /// <returns></returns>
  23. protected override Expression VisitBinary(BinaryExpression node)
  24. {
  25. if (node == null) throw new ArgumentNullException("BinaryExpression");
  26. this._StringStack.Push(")");
  27. base.Visit(node.Right);//解析右边
  28. this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " ");
  29. base.Visit(node.Left);//解析左边
  30. this._StringStack.Push("(");
  31. return node;
  32. }
  33. /// <summary>
  34. ///
  35. /// </summary>
  36. /// <param name="node"></param>
  37. /// <returns></returns>
  38. protected override Expression VisitMember(MemberExpression node)
  39. {
  40. if (node == null) throw new ArgumentNullException("MemberExpression");
  41. this._StringStack.Push(" [" + node.Member.Name + "] ");
  42. return node;
  43. }
  44. /// <summary>
  45. /// 常量表达式
  46. /// </summary>
  47. /// <param name="node"></param>
  48. /// <returns></returns>
  49. protected override Expression VisitConstant(ConstantExpression node)
  50. {
  51. if (node == null) throw new ArgumentNullException("ConstantExpression");
  52. this._StringStack.Push(" '" + node.Value + "' ");
  53. return node;
  54. }
  55. /// <summary>
  56. /// 方法表达式
  57. /// </summary>
  58. /// <param name="m"></param>
  59. /// <returns></returns>
  60. protected override Expression VisitMethodCall(MethodCallExpression m)
  61. {
  62. if (m == null) throw new ArgumentNullException("MethodCallExpression");
  63. string format;
  64. switch (m.Method.Name)
  65. {
  66. case "StartsWith":
  67. format = "({0} LIKE {1}+'%')";
  68. break;
  69. case "Contains":
  70. format = "({0} LIKE '%'+{1}+'%')";
  71. break;
  72. case "EndsWith":
  73. format = "({0} LIKE '%'+{1})";
  74. break;
  75. default:
  76. throw new NotSupportedException(m.NodeType + " is not supported!");
  77. }
  78. this.Visit(m.Object);
  79. this.Visit(m.Arguments[0]);
  80. string right = this._StringStack.Pop();
  81. string left = this._StringStack.Pop();
  82. this._StringStack.Push(String.Format(format, left, right));
  83. return m;
  84. }
  85. }
  86. }
  87. using System;
  88. using System.Collections.Generic;
  89. using System.Linq;
  90. using System.Linq.Expressions;
  91. using System.Text;
  92. using System.Threading.Tasks;
  93. namespace MyDelegateEvent.ExpressionTest
  94. {
  95. internal static class SqlOperator
  96. {
  97. internal static string ToSqlOperator(this ExpressionType type)
  98. {
  99. switch (type)
  100. {
  101. case (ExpressionType.AndAlso):
  102. case (ExpressionType.And):
  103. return "AND";
  104. case (ExpressionType.OrElse):
  105. case (ExpressionType.Or):
  106. return "OR";
  107. case (ExpressionType.Not):
  108. return "NOT";
  109. case (ExpressionType.NotEqual):
  110. return "<>";
  111. case ExpressionType.GreaterThan:
  112. return ">";
  113. case ExpressionType.GreaterThanOrEqual:
  114. return ">=";
  115. case ExpressionType.LessThan:
  116. return "<";
  117. case ExpressionType.LessThanOrEqual:
  118. return "<=";
  119. case (ExpressionType.Equal):
  120. return "=";
  121. default:
  122. throw new Exception("不支持该方法");
  123. }
  124. }
  125. }
  126. }

使用:

  1. {
  2. var userDbSet = new List<Student>().AsQueryable();
  3. var userList = userDbSet.Where(s => s.Id > 100 && s.Name.Contains("1"));
  4. Expression<Func<Student, bool>> predicate = s => s.Id > 100
  5. && s.Name.Contains("1")
  6. && s.Name.StartsWith("2")
  7. && s.Name.EndsWith("3")
  8. && s.QQ > 57265177
  9. && s.QQ < 999999999;
  10. {
  11. //把predicate转成一个where 子句
  12. ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();
  13. visitor.Visit(predicate);
  14. string where = visitor.Condition();
  15. }
  16. }

2.3 LINQ的代码实现

Linq to object(Enumerable):数据源是内存里面的集合—传递的委托判断
Linq to sql(Queryable):数据源在SqlServer—需要Sql语句—从表达式目录树而来的(2.2.2有从表达式目录树转为Sql语句)
自我实现1,通过委托来传递逻辑,来实现List全遍历。
查看源码发现,LINQ的Where是通过迭代器来实现的,重新优化实现逻辑,实现方式通过IEnumerable来进行yield迭代输出:按需获取、延时加载。(发生迭代)需要才进入检查。

  1. 迭代器方法的内部使用状态机实现,但可以使用yield关键字快速实现迭代器方法,使用yield return语句添加需要迭代的元素,在首次迭代时,会一直执行到第一个yield return语句并保存当前迭代状态,在接下来的每次迭代过程中都会从暂停的位置继续执行到下一个yield return语句并保存迭代状态(MoveNext()方法返回true并将当前迭代的值赋值给Current),直到到达迭代器的结尾(MoveNext()方法返回false)完成本次迭代;也可以在迭代过程中使用yield break语句立刻结束本次迭代

image.png
image.png

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace LINQComple {
  8. class Program {
  9. static void Main(string[] args) {
  10. List<Student> students = new List<Student>();
  11. for (int i = 0; i < 30; i++) {
  12. students.Add(new Student() { Age = 28 + i, Name = "Albert_" + i.ToString() });
  13. }
  14. Console.WriteLine("***************Start 这是系统方法*************");
  15. var list = students.Where(s => {
  16. Thread.Sleep(100);
  17. return s.Age > 29;
  18. }); //LINQ
  19. foreach (var item in list) {
  20. Console.WriteLine(item.Name);
  21. }
  22. Console.WriteLine("***************End 这是系统方法*************");
  23. Console.WriteLine("***************Start 这是自定义方法1*************");
  24. var list2 = students.AlbertWhere(s => {
  25. Thread.Sleep(100);
  26. return s.Age > 29;
  27. });
  28. foreach (var item in list2) {
  29. Console.WriteLine(item.Name);
  30. }
  31. Console.WriteLine("***************End 这是自定义方法*************");
  32. Console.WriteLine("***************Start 这是自定义方法2*************");
  33. var ienm = students.AlbertWhereIEnumber(s => {
  34. Thread.Sleep(100);
  35. return s.Age > 29;
  36. });
  37. foreach (var item in ienm) {
  38. Console.WriteLine(item.Name);
  39. }
  40. Console.WriteLine("***************End 这是自定义方法2*************");
  41. }
  42. }
  43. /// <summary>
  44. /// 自己通过委托实现Linq查询
  45. /// if中不同的逻辑需要传递,相当于告诉你要使用委托
  46. /// 1.基于委托封装,完成代码复用
  47. /// </summary>
  48. public static class LinqExtend {
  49. public static List<T> AlbertWhere<T>(this List<T> ts,Func<T, bool> func) {
  50. List<T> ts1 = new List<T>();
  51. foreach (var item in ts) {
  52. if (func.Invoke(item)) {
  53. ts1.Add(item);
  54. }
  55. }
  56. return ts1;
  57. }
  58. /// <summary>
  59. /// 通过枚举迭代,和LINQ原理相同,不会一直在等待查询全部完毕
  60. /// 迭代器升级:按需获取、延时加载。(发生迭代)需要才进入检查
  61. /// </summary>
  62. /// <typeparam name="T"></typeparam>
  63. /// <param name="ts"></param>
  64. /// <param name="func"></param>
  65. /// <returns></returns>
  66. public static IEnumerable<T> AlbertWhereIEnumber<T>(this IEnumerable<T> ts,Func<T,bool> func) {
  67. foreach (var item in ts) {
  68. if (func.Invoke(item)) {
  69. yield return item;
  70. }
  71. }
  72. }
  73. }
  74. public class Student {
  75. public int Age { get; set; }
  76. public string Name { get; set; }
  77. }
  78. }