第九节:委托和事件(1)(委托的发展历史、插件式编程、多播委托)

一. 委托的发展历史和基本用法

  说起委托,每个人可能都会对他有不同的理解,结合实战中委托的使用,我对其理解是:委托和类一样,是用户的一个自定义类型,委托可以有参数、有返回值,委托的关键字是delegate,委托是方法的抽象,有了委托的存在,使得方法可以作为参数传递给另一个方法,同时调用委托的时候,委托所包含的所有方法都会被实现。

  委托的写法由繁琐→简洁,经历了好多过程,大致概括为:new实例化传递方法→直接等于方法名→new实例化中传递匿名方法→省略匿名方法关键字→可以去掉大括号和分号 等等。

  代码如下:

       

复制代码

 1  public class MyDelegate2     {3         //1. 委托的声明4         public delegate void NoReturnNoPara();5         public delegate int WithReturnNoPara();6         public delegate void NoReturnWithPara(int id, string name);7         public delegate MyDelegate WithReturnWithPara(DateTime time);8 9 
10         //2. 委托的使用(在show方法中调用)
11         public void Show()
12         {
13             //以“有参无返回值委托”为例,介绍委托的各种用法
14             //2.1 用法一
15             {
16                 NoReturnWithPara methord = new NoReturnWithPara(this.Test1);
17                 methord.Invoke(1, "唐马儒1");
18             }
19             //2.2 用法二
20             {
21                 NoReturnWithPara methord = this.Test1;
22                 methord.Invoke(2, "唐马儒2");
23             }
24             //2.3 用法三 DotNet 2.0 时代
25             {
26                 NoReturnWithPara methord = new NoReturnWithPara
27                     (
28                     delegate(int id, string name)
29                     {
30                         Console.WriteLine("{0} {1}", id, name);
31                     }
32                     );
33                 methord.Invoke(3, "唐马儒3");
34             }
35             //2.4 用法四 DotNet 3.0 时代
36             {
37                 NoReturnWithPara methord = new NoReturnWithPara
38                     (
39                         (int id, string name) =>
40                         {
41                             Console.WriteLine("{0} {1}", id, name);
42                         }
43                     );
44                 methord.Invoke(4, "唐马儒4");
45             }
46             //2.5 用法五 委托约束
47             {
48                 NoReturnWithPara methord = new NoReturnWithPara
49                     (
50                         (id,name) =>
51                         {
52                             Console.WriteLine("{0} {1}", id, name);
53                         }
54                     );
55                 methord.Invoke(5, "唐马儒5");
56             }
57             //2.6 用法六 (如果方法体只有一行,可以去掉大括号和分号)
58             {
59                 NoReturnWithPara methord = new NoReturnWithPara((id, name) => Console.WriteLine("{0} {1}", id, name));
60                 methord.Invoke(6, "唐马儒6");
61             }
62             //2.7 用法七
63             {
64                 NoReturnWithPara methord = (id, name) => Console.WriteLine("{0} {1}", id, name);
65                 methord.Invoke(7, "唐马儒7");
66                 methord(7, "唐马儒7");
67             }
68             //2.8 用法八
69             {
70                 //Func<int, bool> methord = (x) =>
71                 // {
72                 //     return x > 6;
73                 // };
74                 //等价于(原理,当只有一个参数的时候,可以省略参数的小括号,当方法体只有一行的时候,可以省略大括号和分号,即lambda形式)
75                 Func<int, bool> methord = x => x > 6;
76                 Console.WriteLine(methord.Invoke(8));
77             }
78 
79         }
80         private void Test1(int id, string name)
81         {
82             Console.WriteLine("{0} {1}", id, name);
83         }
84 
85         private void Test2()
86         {
87             Console.WriteLine("DoNothing");
88         }
89 
90         private void Test3()
91         {
92             Console.WriteLine("DoNothing");
93         }
94     }

复制代码

. 解耦、插件式编程

  1. 背景:有一个CarFactory工厂类,可以建造自然吸气发动机、涡轮增压发动机、电动发动机,至于要建造哪个发动机,有多种处理方案。 

   方案(一)通过传递不同的参数来建造不同的发动机

      原理:传递一个参数,根据参数类型来执行不同的逻辑
    缺点:如果增加新的发动机类型,需要修改BuildEngine方法中的内部逻辑,不符合开闭原则

  代码如下:

复制代码

 1   /// <summary>2     /// 这里建一个Car工厂,用来建造三种不同类型的发动机3     /// </summary>4     public class CarFactory5     {6         /// <summary>7         /// 方案一:通过传递不同的参数来建造不同的发动机8         /// 原理:传递一个参数,根据参数类型来执行不同的逻辑9         /// 缺点:如果增加新的发动机类型,需要修改BuildEngine方法中的内部逻辑,不符合开闭原则
10         /// </summary>
11         /// <param name="type">参数类型</param>
12         public static void BuildEngine(EngineType type)
13         {
14             if (type == EngineType.NaturalInspiration)
15             {
16                 Console.WriteLine("建造自然吸气发动机");
17             }
18             else if (type == EngineType.Turbo)
19             {
20                 Console.WriteLine("建造涡轮增压发动机");
21             }
22             else if (type == EngineType.Electric)
23             {
24                 Console.WriteLine("建造电动发动机");
25             }
26         }
27 
28     /// <summary>
29     /// 发动机类型的枚举类
30     /// </summary>
31     public enum EngineType
32     {
33         NaturalInspiration = 0,   //自然吸气
34         Turbo = 1,                //涡轮增压
35         Electric = 2              //电动
36     }
37 }

复制代码

  调用:

1   //1.传统的方式,通过参数类型来区分
2  Console.WriteLine("--------------------------1.传统的方式,通过参数类型来区分------------------------------------");
3 CarFactory.BuildEngine(EngineType.NaturalInspiration);
4 CarFactory.BuildEngine(EngineType.Turbo);
5 CarFactory.BuildEngine(EngineType.Electric);

  结果:

  方案(二):通过传递委托来建造不同的发动机

    原理:传递一个逻辑给我,我去执行

    优点:如果增加新的发动机,只需要单独新增对应建造发动机的方法即可,不需要改变BuildEngine2的内部逻辑,符合开闭原则

   代码如下:

复制代码

 1   public class CarFactory2     {3         /// <summary>4         /// 方案二:通过传递委托来建造不同的发动机5         /// 原理:传递一个逻辑给我,我去执行6         /// 优点:如果增加新的发动机,只需要单独新增对应建造发动机的方法即可,不需要改变BuildEngine2的内部逻辑,符合开闭原则7         /// </summary>8         public static void BuildEngine2(BuildEngineDel be)9         {
10             be.Invoke();
11         }
12         //声明一个无参数的委托
13         public delegate void BuildEngineDel();
14         //下面三个是建造不同发动机的方法
15         public static void BuildNatural()
16         {
17             Console.WriteLine("建造自然吸气发动机");
18         }
19         public static void BuildTurbo()
20         {
21             Console.WriteLine("建造涡轮增压发动机");
22         }
23         public static void BulidElectric()
24         {
25             Console.WriteLine("建造电动发动机");
26         }
27 
28     }
29 }

复制代码

  调用:

复制代码

1     //2.将委托当做参数,进行解耦,实现插件式编程(案例一)
2     Console.WriteLine("--------------------------2.将委托当做参数,进行解耦,实现插件式编程(案例一)------------------------------------");
3      //将方法赋给委托,将委托当做参数传递给新方法
4     CarFactory.BuildEngineDel be1 = CarFactory.BuildNatural;
5     CarFactory.BuildEngine2(be1);
6     CarFactory.BuildEngineDel be2 = CarFactory.BuildTurbo;
7     CarFactory.BuildEngine2(be2);
8     CarFactory.BuildEngineDel be3 = CarFactory.BulidElectric;
9     CarFactory.BuildEngine2(be3);

复制代码

  结果:

 

  2. 背景:现在有一个类,该类要实现对一个int类型的数组中的每个数进行加倍、平方、立方,并输出 

  传统解决方案一:在该类中声明多个方法,分别是加倍、平方、立方的方法

   传统解决方案二:在该类中声明一个万能方法,通过传递不同的参数类型来区分是执行加倍还是平方或者立方操作

   方案三:声明一个万能方法,传递一个委托进来,相当于传递了一个业务逻辑进行,在该方法里只需要执行即可

   代码如下:

复制代码

 1  public class Calculator2     {3         //解决方案三:声明一个万能方法,传递一个委托进来,相当于传递了一个业务逻辑进行,在该方法里只需要执行即可4         /// <summary>5         /// 万能方法6         /// </summary>7         /// <param name="arrs">int类型的数组 </param>8         /// <param name="mydel">系统自带的委托(也可以自定义委托),<int,int>代表:参数和返回值均为int类型</param>9         public static void MySpecMethord(int[] arrs, Func<int,int> mydel)
10         {
11             for (int i = 0; i < arrs.Length; i++)
12             {
13                 arrs[i] = mydel(arrs[i]);
14                 //arrs[i] = mydel.Invoke(arrs[i]);  //等价于上面那句
15                 Console.WriteLine(arrs[i]);
16             }
17         }
18 
19     }

复制代码

   三种调用形式:声明Func委托把方法赋值给它、直接把方法名传递进去、传递lambda方法。

复制代码

 1    Console.WriteLine("--------------------------3.将委托当做参数,进行解耦,实现插件式编程(案例二)------------------------------------");2     int[] arr = { 1, 2, 3, 4, 5 };3     //调用形式一:4    Console.WriteLine("--------------------------调用形式一------------------------------------");5    Func<int, int> mydel = t1;6    Calculator.MySpecMethord(arr, mydel);7     //调用形式二:8     Console.WriteLine("--------------------------调用形式二------------------------------------");9     Calculator.MySpecMethord(arr, t2);
10    //调用形式三:
11     Console.WriteLine("--------------------------调用形式三------------------------------------");
12     Calculator.MySpecMethord(arr, x => x * 2);
13         /// <summary>
14         /// 加倍方法
15         /// </summary>
16         /// <param name="x"></param>
17         /// <returns></returns>
18         public static int t1(int x)
19         {
20             return x * 2;
21         }
22         /// <summary>
23         /// 乘方方法
24         /// </summary>
25         /// <param name="x"></param>
26         /// <returns></returns>
27         public static int t2(int x)
28         {
29             return x * x;
30         }
31         /// <summary>
32         /// 立方方法
33         /// </summary>
34         /// <param name="x"></param>
35         /// <returns></returns>
36         public static int t3(int x)
37         {
38             return x * x * x;
39         }

复制代码

   结果:

 三. 多播委托

  1. 含义:所有的委托的实例都有多播的功能,自定义委托和内置委托都有,可以通过+=和-=给委托增加和删掉不同的方法。

   下面的代码中分别介绍四个不同类别的方法赋值给普通委托和多播委托的形式。

复制代码

 1  public class myMultiDelegate2     {3         //自定义一个没有参数没有返回值的委托4         public delegate void NoReturnNoPara();5 6         /// <summary>7         /// 测试委托常规用法8         /// </summary>9         public void show1()
10         {
11             Student student = new Student();
12             //委托的普通用法,分别调用当前类的实例方法、当前类的静态方法、其他类的实例方法、其他类的静态方法
13             //声明4个委托
14             NoReturnNoPara n1 = this.DoNothing;  //调用当前类的实例方法
15             NoReturnNoPara n2 = myMultiDelegate.DoNothingStatic; //调用当前类的静态方法
16             NoReturnNoPara n3 = student.Study;
17             NoReturnNoPara n4 = Student.StudyAdvanced;
18             
19             //执行
20             n1.Invoke();
21             n2.Invoke();
22             n3.Invoke();
23             n4.Invoke();
24         }
25         /// <summary>
26         /// 测试多播委托的用法
27         /// </summary>
28         public void show2()
29         {
30             //所有的委托的实例都有多播的功能,自定义委托和内置委托都有
31             NoReturnNoPara n1 = this.DoNothing;
32             //+=就是把多个方法按顺序排成列表,invoke时按顺序执行
33             n1 += myMultiDelegate.DoNothingStatic;
34             n1 += Student.StudyAdvanced;
35             n1 += this.DoNothing;
36             n1 += this.DoNothing;
37             n1 += this.DoNothing;
38             n1 += this.DoNothing;
39             //-=就是从这个实例上,从后往前挨个匹配,找到第一个完全吻合的移除掉,且只移除一个,找不到不异常
40             //注意,对于委托,+= 和 -= 对null是不会报错的
41             n1 -= this.DoNothing;  
42             n1.Invoke();
43         }
44 
45 
46         #region 两个供委托调用的测试方法
47         private void DoNothing()
48         {
49             Console.WriteLine("当前类中的实例方法");
50         }
51         private static void DoNothingStatic()
52         {
53             Console.WriteLine("当前类中的静态方法");
54         }
55         #endregion
56     }

复制代码

2. 多播委托的实际使用场景。

 实际注册业务场景:先查询账号是否存在(如果不存在)→向表1中插入信息→向表2中插入信息。。。。,随着业务新需求的变更,注册时需要向表3中插入数据, 过了一段时间,需求又变了,不需要向表2中添加数据了。

  下述代码是一个注册流程的类。

复制代码

 1  public class RegisterUtils2     {3         //传统的解决方案,在一个方法里书写各种业务。4         //缺点:后期需求变更了,当需要插入更多数据的时候,只能修改该方法内部逻辑,不符合开闭原则5 6 7         //下面介绍利用多播委托进行解耦插件式开发8         public delegate void myRegisterDelegate(string userName, string userPwd);9 
10         public static void myRegister(myRegisterDelegate mrd, string userName, string userPwd)
11         {
12             //对密码进行Md5加密后在进行后续操作
13             string md5userPwd = userPwd + "MD5";  //模拟Md5
14             mrd.Invoke(userName, md5userPwd);
15         }
16         /// <summary>
17         /// 查询方法
18         /// </summary>
19         public static void checkIsRegister(string userName, string userPwd)
20         {
21             Console.WriteLine("查询成功");
22         }
23         /// <summary>
24         /// 向表1中插入数据
25         /// </summary>
26         public static void writeTable1(string userName, string userPwd)
27         {
28             Console.WriteLine("向表1中插入数据{0},{1}",userName,userPwd);
29         }
30         /// <summary>
31         /// 向表2中插入数据
32         /// </summary>
33         public static void writeTable2(string userName, string userPwd)
34         {
35             Console.WriteLine("向表2中插入数据{0},{1}", userName, userPwd);
36         }
37         /// <summary>
38         /// 向表3中插入数据
39         /// </summary>
40         public static void writeTable3(string userName, string userPwd)
41         {
42             Console.WriteLine("向表3中插入数据{0},{1}", userName, userPwd);
43         }
44     }

复制代码

调用

复制代码

1    Console.WriteLine("--------------------------3.多播委托的案例(在注册流程中) ------------------------------------");
2                 RegisterUtils.myRegisterDelegate mrd = RegisterUtils.checkIsRegister;
3                 mrd += RegisterUtils.writeTable1;
4                 mrd += RegisterUtils.writeTable2;
5                 //需求增加了,向表3中添加数据
6                 mrd += RegisterUtils.writeTable3;
7                 //需求变更了,删除向表2中添加数据
8                 mrd -= RegisterUtils.writeTable2;
9                 RegisterUtils.myRegister(mrd, "maru", "123");

复制代码

结果:

 

  补充:在下一个章节:.Net进阶系列(7)-委托和事件(二)中,会继续介绍泛型委托、内置委托、委托的其他性质、委托和事件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java为什么不使用odbc_java jdbc和odbc的区别是什么?jdbc和odbc的关系是怎样的?

对于jdbc和odbc你都了解多少呢?今天要给大家讲到的就是jdbc和odbc之间的内容&#xff0c;一起来了解一下jdbc和odbc的区别以及关系是怎样的吧!下面先来给大家介绍一下jdbc和odbc之间的区别。总的来说&#xff0c;jdbc和odbc的区别可以划分成三大部分&#xff0c;一起来看看。一…

第十节:委托和事件(2)(泛型委托、Func和Action、事件及与委托的比较)

一. 泛型委托 所谓的泛型委托&#xff0c;即自定义委托的参数可以用泛型约束&#xff0c;同时内置委托Func和Action本身就是泛型委托。 将上一个章节中的Calculator类中的方法用自定义泛型委托重新实现一下。 1 public class Calculator22 {3 //传统解决方案一&am…

java中sql之count_按SQL Server中的count()子句分组

我正在尝试编写一个SQL查询&#xff0c;它将返回聚合值列表;但是&#xff0c;我想通过其中一个聚合值(计数)对查询进行分组&#xff1a;select t.Field1, count(distinct(t.Field2), SUM(t.Value1)from MyTable tgroup by t.Field1, count(t.Field2)我已经尝试将计数放入子查询…

java+sm4+加密算法_SM4加密算法实现Java和C#相互加密解密

https://www.cnblogs.com/miaoziblog/p/9040473.html近期由于项目需要使用SM4对数据进行加密&#xff0c;然后传给Java后台&#xff0c;Java后台使用的也是SM4的加密算法但是就是解密不正确&#xff0c;经过一步步调试发现Java中好多数据类型与C#的相同的数据类型是存在不同的比…

用java设计节拍器_具有高速的Java节拍器

关于Thread.sleep()不可靠的答案是正确的&#xff1a;你不能指望它完全返回你指定的时间.事实上,我很惊讶你的节拍器可以使用,特别是当你的系统负载不足时.阅读Thread.sleep()的文档以获取更多详细信息.关于MIDI的Max Beikirch的答案是一个很好的建议&#xff1a;MIDI处理时机非…

java隐藏密钥_java – 在Android中隐藏密钥库密码的最佳方法是什么?

我是Android开发和实现SSLSockets的新手.在做了一些挖掘后,我能够设置一个正常工作的简单服务器/客户端.我认为实现可以使用一些工作,并且难以将密码加载到密钥库而不用纯文本.这是客户端的一些代码.如您所见,我将密码硬编码到本地var中.是否有更好的方法加载密钥库密码,所以我…

DotNet进阶系列

一. 回顾历史 回顾个人发展历程&#xff0c;自2012年初次接触开发至今(2018年)已经有六个年头&#xff0c;这期间陆陆续续学习并掌握了不少技术&#xff0c;C#语言、ORM框架、多线程技术、设计模式、前端技术、MVC、MVVM框架思想等等&#xff0c;每种技术随着多次使用&#xff…

美团科技 Java工程师_美团Java工程师面试题(2018秋招)

第一次面试1.小数是怎么存的2.算法题&#xff1a;N二进制有多少个13.Linux命令(不熟悉4.JVM垃圾回收算法5.C或者伪代码实现复制算法6.volatile7.树的先序中序后序以及应用场景8.Mysql存储记录的数据结构9.索引数据结构10.为什么不用AVL和红黑树存&#xff1f;11.说实习项目12.r…

第十一节:特性(常见的特性标签、自定义特性、特性的使用案例)

一. 基本概念 1. 什么是特性? MSDN官方给出的定义时&#xff1a;公共语言运行时允许添加类似关键字的描述声明&#xff0c;叫做特性&#xff0c;它对程序中的元素进行标注&#xff0c;如类型、字段、方法和属性等。Attribute和Microsoft .Net Framework文件的元数据&#xff…

java不建议用全局变量吗_不要使用全局变量, ThreadLocal也不行

不要使用全局变量的道理大家都懂&#xff0c;基本上在大家学习编程过程中很早就会被教育到&#xff0c;但是有时候我们也会禁不住诱惑用到一些似非实是的全局变量&#xff0c;只不过这些全局变量会穿上马甲&#xff0c;让你不会一下看穿它的巨大危害&#xff0c;这里就讲一下我…

第十二节:Lambda、linq、SQL的相爱相杀(1)

一. 谈情怀 Lambda、Linq、SQL伴随着我的开发一年又一年&#xff0c;但它们三者并没有此消彼长&#xff0c;各自占有这一定的比重&#xff0c;起着不可替代的作用。 相信我们最先接触的应该就是SQL了&#xff0c;凡是科班出身的人&#xff0c;大学期间都会学习SQL Server数据库…

php java 共享session_PHP 实现多服务器共享 SESSION 数据

一、问题起源稍大一些的网站&#xff0c;通常都会有好几个服务器&#xff0c;每个服务器运行着不同功能的模块&#xff0c;使用不同的二级域名&#xff0c;而一个整体性强的网站&#xff0c;用户系统是统一的&#xff0c;即一套用户名、密码在整个网站的各个模块中都是可以登录…

第十三节:Lambda、linq、SQL的相爱相杀(2)

一. Linq开篇 1.Where用法 linq中where的用法与SQL中where的用法基本一致。 1 #region 01-where用法2 {3 //1. where用法4 //1.1 查询账号为admin的用户信息5 Console.WriteLine("------------…

asp 调用java文件上传_用asp实现文件浏览、上传、下载的程序

可以放在服务器上&#xff0c;对服务器上的文件进行浏览、上传、下载&#xff0c;可下载文件源码。把下所有代码入在一个文件里即可&#xff0c;文件的后缀要为asp。thedir request("thedir")if thedir "" thenfolderini server.mappath(".")…

第十四节:Lambda、linq、SQL的相爱相杀(3)

一. SQL 开篇 1. where用法 1    #region 封装EF调用SQL语句查询 2 public static List<T> ExecuteQuery<T>(string sql, params SqlParameter[] pars) 3 { 4 return db.Database.SqlQuery<T>(sql, pars).ToList(); 5 …

hive mysql windows_Java-从MySQL到Hive导入,其中MySQL在Windows上运行,而Hive在Cent OS上运行(Horton Sandbox)...

在任何答案和评论之前.我尝试了在Stackoverflow中找到的几个选项,但均以失败告终.以下是这些链接-我通过命令行在Horton Sandbox中进行了尝试并成功.sqoop import --connect jdbc:mysql://192.168.56.101:3316/database_name --usernameuser --passwordpwd --table table_name …

第十五节:Expression表达式目录树(与委托的区别、自行拼接、总结几类实例间的拷贝)

一. 基本介绍 回忆&#xff1a; 最早接触到表达式目录树(Expression)可能要追溯到几年前使用EF早期的时候&#xff0c;发现where方法里的参数是Expression<Func<T,bool>>这么一个类型&#xff0c;当初不是很理解&#xff0c;只是知道传入lambda表达式使用即可&…

Php7 mongodb explain,【代码片-1】 php7 mongoDB 简单封装

/*** mongoDB 简单 封装* 注意&#xff1a;支持 mongoDB 3.2** author color_wind*/finalclassm_mgdb {privatestatic$ins [];privatestatic$def"default";private$_conn null;private$_db null;privatestatic$_config ["default"> ["url">…

IIS Web 服务器/ASP.NET 运行原理基本知识概念整理

前言&#xff1a; 记录 IIS 相关的笔记还是从公司笔试考核题开始的&#xff0c;问 Application Pool 与 AppDomain 的区别&#xff1f; 促使我对进程池进了知识的学习&#xff0c;所以记录一下学习的笔记。 我们知道现在 .NET 就业来看&#xff0c;80% 的 .NET 程序员都是从事 …

java正则表达式 ascii,是否可以检查字符串是否在Java中仅包含ASCII?

使用正则表达式您可以使用以下正则表达式查找特定的String值是否包含ASCII字符-\\A\\p{ASCII}*\\zString类的matches()方法接受正则表达式&#xff0c;并验证当前字符串是否与给定表达式匹配(如果匹配)&#xff0c;则返回true&#xff0c;否则返回false。因此&#xff0c;通过将…