第九节:委托和事件(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,一经查实,立即删除!

相关文章

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

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

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

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

DotNet进阶系列

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

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

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

第十二节: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("------------…

第十四节: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 …

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

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

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

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

Http请求处理流程

从一个页面比如www.xuxiaoyu.net的请求开始如何就能打开blogs页面的呢&#xff1f;这其中发生了什么样的东西&#xff1f; Http请求(Http Request) 当服务器&#xff08;IIS&#xff09;接受到一个Http请求的时候进行以下步骤的处理&#xff1a; 1)服务器获取所请求的页面的后缀…

iis到w3wp的数据流及工作原理

HTTP.sys->IO线程-CLR线程池中的worker线程处理 IO线程只负责把请求交给Worker线程或者放入进程池级别的队列,然后又去HTTP.SYS的队列中处理其它的请求

php云解析播放器,xyplay云解析PHPV3.4.1优化稳定版视频解析

演示地址&#xff1a;如有演示站请以演示为准&#xff0c;无演示站以截图为准,源码太多服务器有限&#xff0c;无法搭建所有源码演示站&#xff0c;请谅解&#xff01;新手购买指导&#xff1a;1.在本站注册账号 丨 2.登录已注册账号充值源码所需金币 丨 3.登录账号下载所需源码…

php version.,PHP_VERSION指什么

PHP_VERSION (string)当前的PHP版本&#xff0c;以字符串形式“ major.minor.release [extra]”表示。 (推荐学习&#xff1a;PHP视频教程)例如&#xff1a;<?php // PHP_VERSION_ID 自 PHP 5.2.7 起有效&#xff0c;// 如果我们的版本低于该版本&#xff0c;则用以下代码来…

C# async 和 await 理解

先假设如下场景&#xff1a; 主函数 Main&#xff0c;循环等待用户输入&#xff1b; 计算函数 Cal&#xff0c;耗时计算大量数据&#xff1b; class Test {static int Main(string[] args){while(true){// 等待用户输入}}public static int Cal() {int sum 0;for (int i …

C# 彻底搞懂async/await

前言 Talk is cheap, Show you the code first&#xff01; private void button1_Click(object sender, EventArgs e) {Console.WriteLine("111 balabala. My Thread ID is :" Thread.CurrentThread.ManagedThreadId);AsyncMethod();Console.WriteLine("222 …

c#之task与thread区别及其使用

1.什么是thread 当我们提及多线程的时候会想到thread和threadpool&#xff0c;这都是异步操作&#xff0c;threadpool其实就是thread的集合&#xff0c;具有很多优势&#xff0c;不过在任务多的时候全局队列会存在竞争而消耗资源。thread默认为前台线程&#xff0c;主程序必须等…

java内存分配和垃圾回收,Java内存分配与垃圾回收

1.JVM管理的内存包含下图所示的几个运行时数据区域&#xff0c;其中方法区和堆为线程共享的数据区域&#xff0c;程序计数器&#xff0c;虚拟机栈以及本地方法栈为线程私有的数据区域。程序计数器&#xff1a;可以看做是当前线程所执行的字节码的行号指示器&#xff0c;告诉字节…

谈谈你对闭包的理解?

闭包这个概念好难理解&#xff0c;身边朋友们好多都稀里糊涂的&#xff0c;稀里糊涂的林老冷希望写下这篇文章能够对稀里糊涂的伙伴们有一些帮助~ 请大家跟我理解一下&#xff0c;如果在一个函数的内部定义了另一个函数&#xff0c;外部的我们叫他外函数&#xff0c;内部的我们…

php有哪些开源社区,PHP开源社区

简介Blade 是 Laravel 提供的一个简单而又强大的模板引擎。和其他流行的 PHP 模板引擎不同&#xff0c;Blade 并不限制你在视图中使用原生 PHP 代码。所有 Blade 视图文件都将被编译成原生的 PHP 代码并缓存起来&#xff0c;除非它被修改&#xff0c;否则不会重新编译&#xff…