第十节:委托和事件(2)(泛型委托、Func和Action、事件及与委托的比较)
一. 泛型委托
所谓的泛型委托,即自定义委托的参数可以用泛型约束,同时内置委托Func和Action本身就是泛型委托。
将上一个章节中的Calculator类中的方法用自定义泛型委托重新实现一下。
- public class Calculator2
- {
- //传统解决方案一:在该类中声明多个方法,分别是加倍、平方、立方的方法
- //传统解决方案二:在该类中声明一个万能方法,通过传递不同的参数类型来区分是执行加倍还是平方或者立方操作
- //解决方案三:声明一个万能方法,传递一个委托进来,相当于传递了一个业务逻辑进行,在该方法里只需要执行即可
- /// <summary>
- /// 万能方法
- /// </summary>
- /// <param name="arrs">int类型的数组 </param>
- /// <param name="mydel">自定义委托</param>
- public delegate T myDel<T>(T t);
- public static void MySpecMethord<T>(T[] arrs, myDel<T> myDel)
- {
- for (int i = ; i < arrs.Length; i++)
- {
- arrs[i] = myDel(arrs[i]);
- //arrs[i] = mydel.Invoke(arrs[i]); //等价于上面那句
- Console.WriteLine(arrs[i]);
- }
- }
- }
二. 内置委托
.Net FrameWork提供两个支持泛型的内置委托,分别是Action和Func,结合lambda表达式,可以提高开发效率
二者的区别:
1.Action只能委托无返回值的方法,支持16个重载(in代表输入参数,该重载没有返回值)
分别是:
* public delegate void Action<in T>(T obj);
* public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
* ......
* public delegate void Action<in T1, in T2,......,in T16>(T1 arg1, T2 arg2,......,T16 arg16);
*
2.Func必须委托有返回值的方法,支持17个重载(注意括号里最后一个代表返回值,in代表输入参数,out代表返回值)
分别是:
* public delegate TResult Func<out TResult>();
* public delegate TResult Func<in T, out TResult>(T arg);
* public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
* ......
* public delegate TResult Func<in T1, in T2,.......in T16 out TResult>(T1 arg1, T2 arg2,......T16 arg16);
*
总结:除了ref参数和out参数,内置委托基本上能适用于任何泛型委托的场景,非常好用
3. 内置委托和自定义委托的区别:
自定义委托需要先声明一下,让系统认识这个自定义委托,然后才能实例化赋值方法;而内置委托系统本事就存在,所有不需要事先声明,直接实例化赋值方法即可
三. 委托的其它性质
静态方法和实例方法对于委托的区别,对于静态方法,Target属性为null,所以效率比实例属性更高
- public class OtherCharacters
- {
- public delegate void mySpecDelegate();
- /// <summary>
- /// 1.测试普通实例方法和静态方法在委托中的区别
- /// </summary>
- public static void Test1()
- {
- MR mr=new MR();
- //实例方法
- mySpecDelegate a = mr.f1;
- Console.WriteLine(a.Target==mr); //true
- //静态方法
- mySpecDelegate b = MR.f2;
- Console.WriteLine(b.Target==null); //true
- }
- }
- public class MR
- {
- /// <summary>
- /// 普通方法
- /// </summary>
- public void f1()
- {
- }
- //静态方法
- public static void f2()
- {
- }
- }
四. 事件
1. 事件介绍
* 定义:声明一个委托实例,然后在该实例的前面加上event关键字,就形成事件了
* 事件的用途:实现广播和订阅的场景
* 1.广播者:包括1个事件字段,独享执行委托的方法
* 2.订阅者:通过调用 += 和 -= 来决定何时开始或停止订阅
* 总结:事件是描述这种场景模式的一个词,事件是委托的一个子集,为了满足“广播/订阅”模式的需求而生
* 事件和委托的区别:
* 1. 委托是一种类型,而事件是委托的一个实例,然后在该实例前加上一个关键字
* 2. 事件有一系列规则和约束用以保证程序的安全可控,事件只有 += 和 -= 操作,这样订阅者只能有订阅或取消订阅操作,没有权限执行其它操作
* 3. 如果是委托,那么订阅者就可以使用 = 来对委托对象重新赋值(其它订阅者全部被取消订阅),甚至将其设置为null,甚至订阅者还可以直接调用委托,这些都是很危险的操作,广播者就失去了独享控制权
* 4. 事件保证了程序的安全性和健壮性
2. 下面代码就事件和委托进行比较
- public class MyEvent
- {
- //下面的案例用委托和事件实现相同的功能
- public Action myDelegate;
- /// <summary>
- /// 触发委托执行的方法
- /// </summary>
- public void realizeDelegate()
- {
- if (myDelegate != null)
- {
- myDelegate.Invoke();
- }
- }
- public event Action myEvent;
- /// <summary>
- /// 触发事件执行的方法
- /// </summary>
- public void realizeEvent()
- {
- if (myEvent != null)
- {
- myEvent.Invoke();
- }
- }
- #region 供委托和事件测试调用的方法
- public static void T1()
- {
- Console.WriteLine("方法一");
- }
- public static void T2()
- {
- Console.WriteLine("方法二");
- }
- public static void T3()
- {
- Console.WriteLine("方法三");
- }
- #endregion
- }
3. 调用时候的区别:
委托中的订阅者可以直接Invoke()来调用委托,而事件中的订阅者不能直接Invoke()调用委托,只能通过广播者中的方法来实现调用委托,从而保证广播者独享控制权。
- {
- Console.WriteLine("--------------------------七. 事件------------------------------------");
- MyEvent m1 = new MyEvent();
- //1. 委托实现
- Console.WriteLine("--------------------------1. 委托实现------------------------------------");
- //订阅者进行订阅
- m1.myDelegate += MyEvent.T1;
- m1.myDelegate += MyEvent.T2;
- m1.myDelegate += MyEvent.T3;
- m1.myDelegate.Invoke(); //委托中的订阅者可以直接调用委托
- m1.myDelegate -= MyEvent.T2;
- m1.realizeDelegate();
- //2. 事件实现
- Console.WriteLine("--------------------------2. 事件实现------------------------------------");
- m1.myEvent += MyEvent.T1;
- m1.myEvent += MyEvent.T2;
- m1.myEvent += MyEvent.T3;
- // m1.myEvent.Invoke(); //事件中的订阅者不能直接调用委托
- m1.realizeEvent(); //只能通过发布者中方法来实现委托,保证发布者独享控制权
- m1.myEvent -= MyEvent.T2;
- m1.realizeEvent();
- }
结果:
第十节:委托和事件(2)(泛型委托、Func和Action、事件及与委托的比较)的更多相关文章
- 第一百二十节,JavaScript事件对象
JavaScript事件对象 学习要点: 1.事件对象 2.鼠标事件 3.键盘事件 4.W3C与IE JavaScript事件的一个重要方面是它们拥有一些相对一致的特点,可以给你的开发提供更多的强大功 ...
- C# 关于委托和事件的妙文:通过一个例子详细介绍委托和事件的作用;Observer模式简介
委托和事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见 ...
- 按自己的想法去理解事件和泛型(C#)
上一篇那些年困扰我们的委托(C#)讲了委托,这一篇自然就轮到事件了. 不喜欢官方的表达方式,喜欢按照自己的想法去理解一些抽象的东西. 事件 考虑到委托使用的一些缺陷,就有了事件.委托是不安全的,打个比 ...
- 第三百五十节,Python分布式爬虫打造搜索引擎Scrapy精讲—selenium模块是一个python操作浏览器软件的一个模块,可以实现js动态网页请求
第三百五十节,Python分布式爬虫打造搜索引擎Scrapy精讲—selenium模块是一个python操作浏览器软件的一个模块,可以实现js动态网页请求 selenium模块 selenium模块为 ...
- centos LAMP第二部分apache配置 下载discuz!配置第一个虚拟主机 安装Discuz! 用户认证 配置域名跳转 配置apache的访问日志 配置静态文件缓存 配置防盗链 访问控制 apache rewrite 配置开机启动apache tcpdump 第二十节课
centos LAMP第二部分apache配置 下载discuz!配置第一个虚拟主机 安装Discuz! 用户认证 配置域名跳转 配置apache的访问日志 配置静态文件缓存 配置防盗链 ...
- centos shell编程6一些工作中实践脚本 nagios监控脚本 自定义zabbix脚本 mysql备份脚本 zabbix错误日志 直接送给bc做计算 gzip innobackupex/Xtrabackup 第四十节课
centos shell编程6一些工作中实践脚本 nagios监控脚本 自定义zabbix脚本 mysql备份脚本 zabbix错误日志 直接送给bc做计算 gzip innobacku ...
- C#编程语言之委托与事件(一)—— C/C++函数指针和C#委托初步
相信正在学习C#的人都有学习过C或C++的经验,本文要讲的第一个要点是C#中的委托(delegate,有些资料也叫代表).什么是委托,很多人都能自然而然地想到C/C++中的函数指针,事实上很多书和资料 ...
- 第十节:详细讲解一下Java多线程,随机文件
前言 大家好,给大家带来第十节:详细讲解一下Java多线程,随机文件的概述,希望你们喜欢 多线程的概念 线程的生命周期 多线程程序的设计 多线程的概念 多线程的概念:程序是静态的,进程是动态的.多进程 ...
- 第三百八十节,Django+Xadmin打造上线标准的在线教育平台—将所有app下的models数据库表注册到xadmin后台管理
第三百八十节,Django+Xadmin打造上线标准的在线教育平台—将所有app下的models数据库表注册到xadmin后台管理 将一个app下的models数据库表注册到xadmin后台管理 重点 ...
随机推荐
- GoldenDict词典的超级实用高级玩法----全文搜索功能
快捷键: Ctrl+Shift+F 菜单进入:搜索--全文搜索 模式:正则表达式 比如:我想知道地道的英文表达 请xx天/周/年假 给搜索框写入正则表达式 请(.)(天|周|年)假 就可以了 ...
- 1.2 NCE22 By heart
Some plays are so successful that they run/are performed/ for years on end/successively/in a row/con ...
- 【Linux基础】Unix与Linux操作系统介绍
一.Unix和Linux操作系统概述 1.Unix是什么 UNIX是一个计算机操作系统,一个用来协调.管理和控制计算机硬件和软件资源的控制程序. 2.Unix特点 (1)多用户:在同一时刻可以有多个用 ...
- Python开发【第四篇】函数
函数的作用 函数可以让编程逻辑结构化以及模块化 无论是C.C++,Java还是Python,函数是必不可少的知识点,也是很重要的知识点,函数是完成一个功能的代码块,使用函数可以使逻辑结构变得更加清晰以 ...
- tian
上次后来没继续在微信上聊,是因为快过年了,想趁那段时间结合年假做点东西.接下来阳历三四月份就受美国制裁.结果接下来制裁.fang. 16年的那次主要是生气,在一块儿 另外经济上也有问题. 我也想过不再 ...
- Java 8 中为什么要引出default方法
(原) default方法是java 8中新引入进的,它充许接口中除了有抽象方法以外,还可以拥用具有实现体的方法,这一点跟jdk8之前的版本已经完全不一样了,为什么要这样做呢? 拿List接口举例,在 ...
- 数据库的设计:深入理解 Realm 的多线程处理机制
你已经阅读过 Realm 关于线程的基础知识.你已经知道了在处理多线程的时候你不需要关心太多东西了,因为强大的 Realm 会帮你处理好这些,但是你还是很想知道更多细节…… 你想知道在 Realm 的 ...
- java 面试题整理(不定期更新)
一.Java基础 1.Java面向对象的三个特征与含义 三大特征是:封装.继承和多态. 封装是指将某事物的属性和行为包装到对象中,这个对象只对外公布需要公开的属性和行为,而这个公布也是可以有选择性的公 ...
- BZOJ3328 PYXFIB 单位根反演
题意:求 \[ \sum_{i=0}^n[k|i]\binom{n}{i}Fib(i) \] 斐波那契数列有简单的矩阵上的通项公式\(Fib(n)=A^n_{1,1}\).代入得 \[ =\sum_{ ...
- OracleSql语句学习(三)
--在SELECT子句中出现的函数或表达式会在结果集中作为字段名,这样的可读性差,因此可以为--这样的字段添加别名(别名中不能出现空隔,除非是用双引号括起来的)--别名中如果希望包含空隔或者区分大小写 ...