委托和事件详解

委托和事件详解

  • 前言
  • 一、委托
    • 1.什么是委托
    • 2.委托的声明
    • 3.Action<T>委托和Func<T>委托
    • 4.委托的缺点
    • 5.委托与lambda表达式
    • 6.委托的使用
      • (1)模板方法
      • (2)回调方法
  • 二、事件
    • 1.什么是事件
    • 2.事件模型的5个步骤和组成部分
      • (1)5个步骤
      • (2)5个组成部分
    • 3.实际案例
    • 4.事件语法
    • 5.事件是基于委托的
    • 6.Q&A


前言

这篇委托和事件的学习笔记是基于b站BeaverJoe大佬的视频学习整理的,老师主页还有很多案例教程可供学习~BeaverJoe主页链接


一、委托

1.什么是委托

委托是一种类,引用类型的数据类型。它有返回值类型和参数列表,可以指向一个或多个方法。
当实例化委托后(即创建了一个委托的实例),这个委托类型的实例可以和任何其他方法关联起来,存储这些方法(即 目标方法)的引用(前提是类型兼容),接着就可以通过委托类型的实例 间接调用这些存储的方法(invoke)

2.委托的声明

委托虽然是一种类,但它的声明格式却更接近于方法(这是因为仿造了c语言中函数指针的声明方式)。委托可以声明在类中,因为c#支持嵌套类,此时委托就是一个类的嵌套类。
在这里插入图片描述
【注1】可以省略写法(直接将方法赋值给委托类型变量):

//多播委托
myDelegate+=ChangeColor;
myDelegate+=Log;

【注2】封装的是有参数列表的方法的话,在调用委托时就要传入参数:

myDelegate01("James",3);
myDelegate01("Curry",3);

【注3】自定义声明委托时需要加上delegate关键词,但不是所有委托声明都需要使用delegate关键词,因为c#类库中已经准备好了两个委托Action和Func

3.Action委托和Func委托

可以省去声明委托类型的步骤,直接使用内置委托类型来声明创建变量。
【注】使用时要引入命名空间System
Action< T >: 指向返回值为空,参数列表为空或者有参数列表(最多16个参数)的方法
在这里插入图片描述
Func< T >:指向有返回值,参数列表为空或者有参数列表(最多16个参数)的方法,且返回值一定要放在<>中最后一位
在这里插入图片描述

4.委托的缺点

(1)安全性上:即使可以通过多播委托来调用很多其他的方法,但也是很不安全的,如果把+=写成了=,就覆盖了之前的所有方法,提高了项目维护成本。
(2)关于内存泄漏:委托会引用一个方法,如果这个方法是一个实例方法(非静态方法)的话,那么这个方法就一定隶属于一个对象,拿一个委托引用这个方法,那么这个对象就必须存在在内存中,即使没有其他引用变量引用这个对象了,这个对象的内存也不能被释放。因为一旦释放内存,委托就不能再间接调用对象的方法了,所以说委托容易造成内存泄漏(memory leak),随着内存泄漏越来越多,程序就会面临崩溃。
(3)可读性上:如果在委托内部又嵌套了别的委托,debug难度就会上升,可读性也较差了。

5.委托与lambda表达式

未使用lambda表达式前:
在这里插入图片描述
使用lambda表达式:
lambda表达式真正的作用就是可以省去【创建方法】这一步骤,将Lambda表达式作为一个实际参数,传递到方法中
在这里插入图片描述

6.委托的使用

(1)模板方法

类可以作为方法的参数类型,而委托是一种类,所以可以把委托当作方法的参数,将指向的目标方法传递到另一个方法中去,就形成了一种动态调用方法的代码结构(根据不同的游戏需求,传递不同的委托类型封装的方法,达到动态调用的效果)。
而模板方法就是有一处不确定,其余代码都是确定好的,这个不确定的部分,就靠我们传进来的委托类型的参数所包含的这个方法来填补。

(2)回调方法

所谓的回调关系:某个方法,可以去调用它,也可以不去调用它,用得着的时候就去调用这个方法。
以回调方法形式使用【委托】,需要把委托类型作为参数传入到方法中,被传进方法的委托类型参数内部封装了一个被回调的方法,也就是回调方法,我们的方法会根据自己的逻辑来决定是不是要调用这个回调方法。
【注】一般回调方法都会放在方法代码的末尾之处,且一般回调方法都是没有返回值的
在这里插入图片描述

二、事件

1.什么是事件

事件的定义:当某件有趣的事情发生时,一个类或者对象中的事件就会通知(关心这件事情的)别的类、别的对象“这里有件有趣的事情发生啦!”,别的类、别的对象就会纷纷做出各自的响应
【注】事件必定是一个对象、类的成员,就像“死亡”必须基于“玩家”/“敌人”,“开花”必须基于“花”,“发布”必须基于“新游戏”一样,事件可以“发生”,核心功能是通知别人,发生效果。

2.事件模型的5个步骤和组成部分

(1)5个步骤

事件模型包含5个步骤:
Step1:我(类)要有一个事件(成员)
Step2:一群别的类关心、订阅我的事件
Step3:我的事件发生了!
Step4:关心的类们被一次性通知到
Step5:被通知到的人,拿着事件参数,做出响应

(2)5个组成部分

A、事件的拥有者: 事件的源头,事件的拥有者一定是一个类(或者说是对象),谁拥有事件,谁就是事件的拥有者

B、事件: 一个类的成员类型,是一种让【事件的拥有者】具有通知能力的成员。事件不会主动发生,一定是由事件拥有者的内部逻辑触发

C、事件的响应者: 订阅事件的类、对象们

D、事件处理器: 通过通知和事件参数,而采取行动的行为称为“响应事件”或者“处理事件”,而处理事件时具体做的这些事情(事件响应者处理事件的方法成员),就叫做“事件处理器(EventHandler)”
【注】所谓的约定,就是指这个方法必须和声明事件的时候,会使用的委托类型相匹配(事件基于委托)

E、事件订阅(+=操作符): 事件处理器的【返回值】和【参数列表】必须和事件的【委托类型】保持一致
【注】事件有订阅,就一定有取消订阅,两者是配套出现的,以防内存泄漏的问题
在这里插入图片描述

3.实际案例

在这里插入图片描述

4.事件语法

自定义事件声明格式(完整 / 简略形式)
完整声明格式:
在这里插入图片描述
简略声明格式:(像委托类型字段但不是,事件的本质是委托类型字段的包装器,限制了外部对内部的委托字段的访问,只让访问+=和-=两个操作,而不能直接调用)
在这里插入图片描述
优化后:
在这里插入图片描述

5.事件是基于委托的

【事件是基于委托的】有两层意思:
(1)类型兼容。 事件需要委托类型来做一个约束,这个约束既规定了事件它能发送什么样的消息给事件响应者,同时也规定了事件响应者能收到什么样的消息。事件处理器的【返回值】和【参数列表】必须和事件的【委托类型】保持一致,才能订阅这个事件
(2)存储方法的引用。 当事件的响应者向事件的拥有者提供了一个与之匹配事件的事件处理器之后,就需要一个地方,把这个事件处理器以及之后这些事件处理器保存、储存、记录下来,而只有委托类型的实例能办到这点。

6.Q&A

Q:委托和事件的关系是什么?
A:事件不是特殊的委托类型字段,它只是委托类型字段的包装器,限制外界对委托类型的字段的访问,外界只能去访问他的+=、-=操作符(只能添加/移除事件处理器)

Q:为什么要使用委托类型来声明事件?(换句话说:为什么事件是基于委托的?)
A:当事件的响应者向事件的拥有者提供了一个与之匹配事件的事件处理器之后,就需要一个地方,把这个事件处理器以及之后这些事件处理器保存、储存、记录下来,而只有委托类型的实例能办到这点。

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UE5 播放本地MP3、MP4

1.创建一个媒体播放器 2.如创建视频&#xff0c;勾选。 它会多一个媒体纹理给你 3.1 设置音频 在一个actor上添加“媒体音频组件” “音频媒体播放器”赋值给它 3.2播放音频 添加一个音频媒体播放器变量&#xff0c; 赋值 地址使用绝对地址 4.1设置视频 UI上创建一个imag…

Linux第49步_移植ST公司的linux内核第1步_获取linux源码

已知ST公司的linux源码路径&#xff1a; /home/zgq/linux/atk-mp1/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0 1、创建“my_linux”目录 打开第1个终端 输入“ls回车” 输入“cd linux/回车”&#xff0c;切换…

C语言每日一题(55)另一颗树的子树

力扣 572 另一棵树的子树 题目描述 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所…

C#,最大公共子序列(LCS,Longest Common Subsequences)的算法与源代码

1 最大公共子序列 最长的常见子序列问题是寻找两个给定字符串中存在的最长序列。 最大公共子序列算法&#xff0c;常用于犯罪鉴定、亲子鉴定等等的 DNA 比对。 1.1 子序列 让我们考虑一个序列S<s1&#xff0c;s2&#xff0c;s3&#xff0c;s4&#xff0c;…&#xff0c;…

python+django学习交流论坛系统244t6

系统可以提供信息显示和相应服务&#xff0c;其管理员管理用户发布的博客文章以及用户之间的论坛交流信息&#xff0c;管理留言以及文章分类信息。用户在论坛交流模块发布帖子以及评论帖子&#xff0c;在前台查看和评论其他用户发布的博客文章&#xff0c;收藏博客文章&#xf…

给定具体日期 返回给定日期是星期几 calendar.weekday(year,month,day)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 给定具体日期 返回给定日期是星期几 calendar.weekday(year,month,day) [太阳]选择题 如果2024年2月12日是星期一&#xff0c;请问最后一个print语句的运行结果是&#xff1f; import calenda…

ubuntu远程桌面配置以及常见问题

ubuntu桌面系统配置 ubuntu远程桌面配置如下 第一步&#xff0c;安装xrdp sudo apt-get isntall xrdp安装完检查一下服务是否可以正常启动&#xff0c; sudo systemctl status xrdp如果看到active应该就正常启动了 第二步&#xff0c;开启Ubuntu桌面共享 好接下来我们测试一…

【玩转408数据结构】线性表——线性表的顺序表示(顺序表)

知识回顾 通过前文&#xff0c;我们了解到线性表是具有相同数据类型的有限个数据元素序列&#xff1b;并且&#xff0c;线性表只是一种逻辑结构&#xff0c;其不同存储形式所展现出的也略有不同&#xff0c;那么今天我们来了解一下线性表的顺序存储——顺序表。 顺序表的定义 …

Linux:信号的处理

文章目录 信号处理 本篇总结的是关于信号的处理 信号处理 在之前有这样的观点&#xff1a;信号在合适的时候被处理好&#xff0c;当进程收到信号后&#xff0c;当前进程可能在做优先级更高的事&#xff0c;所以它来不及处理这个信号&#xff0c;那么就会把这个信号暂时保存起…

Apache 神禹(shenyu)源码阅读(一)——Admin向Gateway的数据同步(Admin端)

源码版本&#xff1a;2.6.1 单机源码启动项目 启动教程&#xff1a;社区新人开发者启动及开发防踩坑指南 源码阅读 前言 开了个新坑&#xff0c;也是第一次阅读大型项目源码&#xff0c;写文章记录。 在写文章前&#xff0c;已经跑了 Divide 插件体验了一下&#xff08;体…

SpringCloud-项目引入Nacos

一、安装Nacos服务 首先&#xff0c;我们需要从 Nacos 的官方网站下载发布版本。下载地址&#xff1a;Releases alibaba/nacos GitHub 选择合适的版本并下载&#xff0c;解压缩得到 Nacos 的安装包。 在解压后的 Nacos 目录中&#xff0c;找到 bin 文件夹。 用写字板编辑…

python学习23

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

Centos7离线安装MySQL5.7

卸载mariadb rpm -e --nodeps mariadb-libs可以使用rpm -qa|grep mariadb命令检测是否卸载完成。 关闭selinux 将/etc/selinux/config文件中的SELINUX设置为disabled下载MySql的相关rpm包 打开https://dev.mysql.com/downloads/mysql/ 选择Red Hat Enterprise Linux / Oracle L…

Codeforces Round 924 E. Modular Sequence

E. Modular Sequence 题意 对于一个长度为 n n n 的数组 a a a&#xff0c;定义它是 g o o d good good 的当且仅当&#xff1a; a 1 x a_1 x a1​x a i a i − 1 y a_{i} a_{i - 1} y ai​ai−1​y 或 a i a i − 1 m o d y i ≥ 2 a_{i} a_{i - 1} mod \hspace{…

kali最新最简单安装

之前都是用iso镜像文件的 今年好多东西都删库了&#xff0c;所有还是要主要资源的保存 去官网找下载 一般来说都是用虚拟机的 下载完会是一个压缩文件&#xff0c; 解压&#xff0c;然后操作之前需要先下载虚拟机 打开方式用虚拟机打开 kali就按装好了

【Java EE初阶十二】网络编程TCP/IP协议(一)

1. 网络编程 通过网络&#xff0c;让两个主机之间能够进行通信->就这样的通信来完成一定的功能&#xff0c;进行网络编程的时候&#xff0c;需要操作系统给咱们提供一组API&#xff0c;通过这些API来完成编程&#xff1b;API可以认为是应用层和传输层之间交互的路径&#xf…

STM32 cubemx配置DMA+空闲中断接收不定长数据

文章目录 前言一、串口空闲中断二、DMA空闲中断接收不定长数据实现思路三、STM32Cubemx配置DMA空闲中断接收不定长数据四、代码编写总结 前言 本篇文章给大家讲解一下DMA串口空闲中断接收串口不定长数据&#xff0c;之前我们也是讲解过串口接收不定长数据的&#xff0c;那么本…

详细分析Redis中数值乱码的根本原因以及解决方式

目录 前言1. 问题所示2. 原理分析3. 拓展 前言 对于这方面的相关知识推荐阅读&#xff1a; Redis框架从入门到学精&#xff08;全&#xff09;Java关于RedisTemplate的使用分析 附代码java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09; …

力扣 第 383 场周赛 解题报告 | KMP

力扣 第 383 场周赛 解题报告 | KMP 链接 前言 一个人能走的多远不在于他在顺境时能走的多快&#xff0c;而在于他在逆境时多久能找到曾经的自己。 T1 修改矩阵 思路&#xff1a;模拟 时间复杂度&#xff1a; O ( m n ) O(mn) O(mn) class Solution:def modifiedMatrix(se…

读书笔记之《重塑大脑重塑人生》:大脑强大的可塑性

《重塑大脑重塑人生》作者是诺曼道伊奇&#xff0c;原作名: The Brain That Changes Itself: Stories of Personal Triumph from the Frontiers of Brain Science &#xff0c;于 2015-1-20出版。 诺曼•道伊奇&#xff08;Norman Doidge&#xff09;是医学博士&#xff0c;精…