1、委托Delegate实质
由一个修饰符+ delegate,跟方法的定义比较类似,也需要声明参数和返回值。声明一个委托,就是声明一种方法签名(参数+返回值),只要是和声明委托方法签名相同的方法,都可以被委托实例托管。
理解:具有相同方法签名的方法(method),他们的调用都可以通过相同方法签名的委托(class)去实现
比如现在有很多排队的需求:排队买奶茶、排队拿号买房。。。,这些需求可让一个排队服务机构去完成,这个机构只需要定义一项委托服务:指派一个人去排队获取xxx
public delegate object WaitGetAccesss(Person person)
还比如快递服务是不是也是类似的场景,快递的本质是把东西从地点A搬运到地点B,同样可以定义public delegate void WaitGetAccesss(object obj,area A,area B);只需要告知要运输的货物、起始地点A、目的地点B即可(这里只针对运输的部分,不包含派送的部分)
几乎所有的快递运输都可以通过这个方式去完成,无论是数码产品、食品这些
自己能做的事情,让这个排队服务机构完成,这不就是现实世界里委托的含义吗?
public delegate void MyFirstDelegate()
委托的实质是一个类,通过反编译得到MyFirstDelegate如下,这个类继承MulticastDelegate,类的内部包含ctor的构造函数,Invoke、BeginInvoke、EndInvoke方法
.class nested public auto ansi sealed MyFirstDelegate extends [System.Runtime]System.MulticastDelegate { // Methods .method public hidebysig specialname rtspecialname instance void .ctor ( object 'object', native int 'method' ) runtime managed { } // end of method MyFirstDelegate::.ctor .method public hidebysig newslot virtual instance int32 Invoke ( int32 x, int32 y ) runtime managed { } // end of method MyFirstDelegate::Invoke .method public hidebysig newslot virtual instance class [System.Runtime]System.IAsyncResult BeginInvoke ( int32 x, int32 y, class [System.Runtime]System.AsyncCallback callback, object 'object' ) runtime managed { } // end of method MyFirstDelegate::BeginInvoke .method public hidebysig newslot virtual instance int32 EndInvoke ( class [System.Runtime]System.IAsyncResult result ) runtime managed { } // end of method MyFirstDelegate::EndInvoke } // end of class MyFirstDelegate
2、委托的定义及执行
定义
委托的参数方法的签名要和委托的方法签名一致(即要有相同的参数及返回值)
public delegate int NumberHandleDelegate(int a,int b); public static int AddNum(int a, int b) { return a+b; } //标准写法 NumberHandleDelegate numberHandleDelegate1 = new NumberHandleDelegate(AddNum); //语法糖,编译器使用的便捷功能,帮忙省略了new NumberHandleDelegate的编写 NumberHandleDelegate numberHandleDelegate2 = AddNum; //lambda表达式(匿名方法) NumberHandleDelegate numberHandleDelegate3 = (int a, int b) => a + b;
执行
{ Student s = new Student(); int num = s.numberHandleDelegate1.Invoke(3, 5); Console.WriteLine($"num:{num}"); //结果打印:num:8 }
3、实际的应用
3.1应用一
public enum PersonType { Student = 1, Teacher = 2 }
现在想针对不同的人有不同的打招呼的方式,有以下两种方案
//方案1:定义枚举,通过枚举判断,分别给出不同的问候方式; public void SayHi(PersonType type) { switch (type) { case PersonType.Student: Console.WriteLine("同学好"); break; case PersonType.Teacher: Console.WriteLine("老师好"); break; default: throw new Exception("没有找到具体类型"); } } //方案2:根据不同的类型的人,分别定义不同的问候方式 public void SayStudentHi() { Console.WriteLine("同学好"); } public void SayTeacherHi() { Console.WriteLine("老师好"); }
优劣分析
//场景1:如果增加一个类型的人 //方案1:多种分支判断 ---如果增加一个类型的人------增加一个校长;---校长好! // 问题:SayHi方法不稳定,一旦增加一个类型的人;SayHi方法就需要修改;方法的所有逻辑都选哟重新测试. 一个方法中有多种业务逻辑---业务逻辑耦合 //方案2:每个方法都式独立的: // 问题:---如果增加一个类型的人---增加一个方法;功能独立,对其他的功能内部不影响; //场景2:如果需要增加一个功能的业务逻辑呢?--打招呼后再握手 //方案1:增加功能的业务逻辑很方便;只需要在方法内加上 Console.WriteLine("握手"); //方案2:增加公共逻辑--每个方法都需要增加--增加的代码都是一样的,----大量的重复代码;
利用委托能覆盖以上两种场景,完美解决以上问题
//定义一个打招呼的委托 public delegate void SayHiDelegate(); //定义一个公共方法,参数为打招呼的委托 public void SayHiPerfect(SayHiDelegate sayHiDelegate) { sayHiDelegate.Invoke(); Console.WriteLine("握手"); }
调用:
//方案三: student.SayHiPerfect(student.SayStudentHi); student.SayHiPerfect(student.SayTeacherHi);
3.2应用二、面向切面编程