2.1 委托的使用
能够解耦&代码重用
public void SayHi(string name,SayHiDelegate method){//公共方法.....method.Invoke(name);//公共方法....}
多波委托拆解后的异步调用
public delegate void TestFun();static void Main(string[] args) {//多播委托TestFun testFun = new TestFun(() => Console.WriteLine("Hello World"));testFun += new TestFun(() => Console.WriteLine("Hello World"));testFun+= new TestFun(() => Console.WriteLine("Hello World"));testFun.Invoke();//多播委托无法进行异步调用,可通过此方法进行拆解foreach (TestFun item in testFun.GetInvocationList()) {item.BeginInvoke(null,null);}}}
2.2 Lambda
参数列表=>方法体,Lambda表达式就是一个匿名方法,就是一个方法。
基于lambda表达式注册的多播委托是无法移除的。
2.2.1 发展过程
public void delegate SayHiDelegate(string name);public void SayHi(string name){Console.WriteLine($"Say Hi,{name}");}//.NET Framework1.0SayHiDelegate sayHi = new SayHiDelegate(this.SayHi);sayHi.Invoke("Albert");//.NET Framework2.0 匿名方法SayHiDelegate sayHi = new SayHiDelegate(delegate (string name){Console.WriteLine($"Say Hi,{name}");});sayHi.Invoke("Albert");//.NET Framework3.0 delegate变为=>//lambda参数类型可以推断出来,可省略。根据委托的约束来推断出的。 语法糖SayHiDelegate sayHi = new SayHiDelegate(name =>{Console.WriteLine($"Say Hi,{name}");});sayHi.Invoke("Albert");//如果方法体只有一行,可以省略大括号+分号 语法糖SayHiDelegate sayHi = new SayHiDelegate(name =>Console.WriteLine($"Say Hi,{name}"));sayHi.Invoke("Albert");//实例化委托时,可以省略new SayHiDelegate 语法糖SayHiDelegate sayHi = name =>Console.WriteLine($"Say Hi,{name}");sayHi.Invoke("Albert");
2.2.2 对Lambda用于表达式目录树进行解析
解析类
ConditionBuilderVistor.cs ConditionBuilderVisitor.cs
SqlOperator.csSqlOperator.cs
using System;using System.Collections.Generic;using System.Linq;using System.Linq.Expressions;using System.Text;using System.Threading.Tasks;namespace MyDelegateEvent.ExpressionTest{public class ConditionBuilderVisitor : ExpressionVisitor{private Stack<string> _StringStack = new Stack<string>();public string Condition(){string condition = string.Concat(this._StringStack.ToArray());this._StringStack.Clear();return condition;}/// <summary>/// 二元表达式/// </summary>/// <param name="node"></param>/// <returns></returns>protected override Expression VisitBinary(BinaryExpression node){if (node == null) throw new ArgumentNullException("BinaryExpression");this._StringStack.Push(")");base.Visit(node.Right);//解析右边this._StringStack.Push(" " + node.NodeType.ToSqlOperator() + " ");base.Visit(node.Left);//解析左边this._StringStack.Push("(");return node;}/// <summary>////// </summary>/// <param name="node"></param>/// <returns></returns>protected override Expression VisitMember(MemberExpression node){if (node == null) throw new ArgumentNullException("MemberExpression");this._StringStack.Push(" [" + node.Member.Name + "] ");return node;}/// <summary>/// 常量表达式/// </summary>/// <param name="node"></param>/// <returns></returns>protected override Expression VisitConstant(ConstantExpression node){if (node == null) throw new ArgumentNullException("ConstantExpression");this._StringStack.Push(" '" + node.Value + "' ");return node;}/// <summary>/// 方法表达式/// </summary>/// <param name="m"></param>/// <returns></returns>protected override Expression VisitMethodCall(MethodCallExpression m){if (m == null) throw new ArgumentNullException("MethodCallExpression");string format;switch (m.Method.Name){case "StartsWith":format = "({0} LIKE {1}+'%')";break;case "Contains":format = "({0} LIKE '%'+{1}+'%')";break;case "EndsWith":format = "({0} LIKE '%'+{1})";break;default:throw new NotSupportedException(m.NodeType + " is not supported!");}this.Visit(m.Object);this.Visit(m.Arguments[0]);string right = this._StringStack.Pop();string left = this._StringStack.Pop();this._StringStack.Push(String.Format(format, left, right));return m;}}}using System;using System.Collections.Generic;using System.Linq;using System.Linq.Expressions;using System.Text;using System.Threading.Tasks;namespace MyDelegateEvent.ExpressionTest{internal static class SqlOperator{internal static string ToSqlOperator(this ExpressionType type){switch (type){case (ExpressionType.AndAlso):case (ExpressionType.And):return "AND";case (ExpressionType.OrElse):case (ExpressionType.Or):return "OR";case (ExpressionType.Not):return "NOT";case (ExpressionType.NotEqual):return "<>";case ExpressionType.GreaterThan:return ">";case ExpressionType.GreaterThanOrEqual:return ">=";case ExpressionType.LessThan:return "<";case ExpressionType.LessThanOrEqual:return "<=";case (ExpressionType.Equal):return "=";default:throw new Exception("不支持该方法");}}}}
使用:
{var userDbSet = new List<Student>().AsQueryable();var userList = userDbSet.Where(s => s.Id > 100 && s.Name.Contains("1"));Expression<Func<Student, bool>> predicate = s => s.Id > 100&& s.Name.Contains("1")&& s.Name.StartsWith("2")&& s.Name.EndsWith("3")&& s.QQ > 57265177&& s.QQ < 999999999;{//把predicate转成一个where 子句ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();visitor.Visit(predicate);string where = visitor.Condition();}}
2.3 LINQ的代码实现
Linq to object(Enumerable):数据源是内存里面的集合—传递的委托判断
Linq to sql(Queryable):数据源在SqlServer—需要Sql语句—从表达式目录树而来的(2.2.2有从表达式目录树转为Sql语句)
自我实现1,通过委托来传递逻辑,来实现List全遍历。
查看源码发现,LINQ的Where是通过迭代器来实现的,重新优化实现逻辑,实现方式通过IEnumerable来进行yield迭代输出:按需获取、延时加载。(发生迭代)需要才进入检查。
迭代器方法的内部使用状态机实现,但可以使用yield关键字快速实现迭代器方法,使用yield return语句添加需要迭代的元素,在首次迭代时,会一直执行到第一个yield return语句并保存当前迭代状态,在接下来的每次迭代过程中都会从暂停的位置继续执行到下一个yield return语句并保存迭代状态(MoveNext()方法返回true并将当前迭代的值赋值给Current),直到到达迭代器的结尾(MoveNext()方法返回false)完成本次迭代;也可以在迭代过程中使用yield break语句立刻结束本次迭代


using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace LINQComple {class Program {static void Main(string[] args) {List<Student> students = new List<Student>();for (int i = 0; i < 30; i++) {students.Add(new Student() { Age = 28 + i, Name = "Albert_" + i.ToString() });}Console.WriteLine("***************Start 这是系统方法*************");var list = students.Where(s => {Thread.Sleep(100);return s.Age > 29;}); //LINQforeach (var item in list) {Console.WriteLine(item.Name);}Console.WriteLine("***************End 这是系统方法*************");Console.WriteLine("***************Start 这是自定义方法1*************");var list2 = students.AlbertWhere(s => {Thread.Sleep(100);return s.Age > 29;});foreach (var item in list2) {Console.WriteLine(item.Name);}Console.WriteLine("***************End 这是自定义方法*************");Console.WriteLine("***************Start 这是自定义方法2*************");var ienm = students.AlbertWhereIEnumber(s => {Thread.Sleep(100);return s.Age > 29;});foreach (var item in ienm) {Console.WriteLine(item.Name);}Console.WriteLine("***************End 这是自定义方法2*************");}}/// <summary>/// 自己通过委托实现Linq查询/// if中不同的逻辑需要传递,相当于告诉你要使用委托/// 1.基于委托封装,完成代码复用/// </summary>public static class LinqExtend {public static List<T> AlbertWhere<T>(this List<T> ts,Func<T, bool> func) {List<T> ts1 = new List<T>();foreach (var item in ts) {if (func.Invoke(item)) {ts1.Add(item);}}return ts1;}/// <summary>/// 通过枚举迭代,和LINQ原理相同,不会一直在等待查询全部完毕/// 迭代器升级:按需获取、延时加载。(发生迭代)需要才进入检查/// </summary>/// <typeparam name="T"></typeparam>/// <param name="ts"></param>/// <param name="func"></param>/// <returns></returns>public static IEnumerable<T> AlbertWhereIEnumber<T>(this IEnumerable<T> ts,Func<T,bool> func) {foreach (var item in ts) {if (func.Invoke(item)) {yield return item;}}}}public class Student {public int Age { get; set; }public string Name { get; set; }}}
