C#中委托和事件的区别

2023-05-16

言简意赅的解释

先说总结:事件就是委托链(也就是继承自MulticastDelegate类的委托,用delegate声明的委托就是继承自MulticastDelegate类的)的属性,事件有一个Add方法、一个Remove方法以及一个私有委托链。也就是说,声明一个事件,类似于声明一个进行封装了的委托链。

很多人说:“总是感觉委托和事件没什么区别,调用事件不就是相当于调用多个委托么?”
不全对,事件之于委托,就相当于,集合的属性之于集合的元素,注意:事件封装了私有委托链,事件其实就是一个特殊的多播委托(也叫委托链)。

举个例子:

class Program
{
	public delegate void SendHandler(string str); // 用delegate声明的委托就是继承自MulticastDelegate类的
	public event SendHandler SendEvent; // 用刚声明的委托类型来声明事件
	static void Main(string[] args)
	{ }
}

编译后,用ILDASM.EXE打开那个.exe,就会发现SendHandler委托被编译为了一个叫做SendHandler的类,声明的委托就是一个类嘛。
在这里插入图片描述
SendEvent事件则是被编译成了包含一个add_前缀的方法(通过调用Delegate.Combine()方法来实现)和一个remove_前缀的方法(通过调用Delegate.Remove()方法来实现)。这是默认实现,事件是可以自行重写add和remove的。

好了,前面说的都不是废话,你还会看到一个私有字段SendEvent(蔚蓝色菱形),其存储了对事件处理方法的引用。而add_前缀方法和remove_前缀方法起到的就是类似C#属性访问器中get_和set_方法的封装私有字段的作用,使用事件能访问私有委托。简而言之,事件就是用来访问私有的委托字段,让应用程序的代码更加的安全。

浅显易懂的解释

委托

这个可以简单的理解为:把方法当成方法的参数,看起来有点绕口,咱们先写个“你好,世界!”

public void HelloWorld(string name)
{
    ByEnglish(name);
}
public void ByEnglish(string name)
{
    Console.WriteLine("Hello World By" + name);
}

先把这两个方法写出来,先别问为啥这么写好了,现在产品经理打算整个中文版的,好,咱改!

public void ByChinese(string name)
{
    Console.WriteLine("你好,世界!作者:" + name);
}

很明显,上面的HelloWorld()得改了

public enum Language
{
    English,CHinese
}
public void HelloWorld(string name,Language lan)
{
    switch(lan)
    {
        case Language.English:ByEnglish(string name);break;
        case Language.Chinese:ByChinese(string name);break;
    }
}

差不多这样的话可以满足目前的需求了现在突然又蹦出来个意大利人想弄出个意大利版(我不会意大利语,不贴了),按照上面的思路,大概也能整出来。然后,产品经理说:这个方法咱要全球化,每个语言都要照顾到。(NMB) 按照上面的思路来,我觉得可以抽刀砍人了。但是法律这玩意儿可怕哟,想到这个我的心儿就碎了。所以咱们还是把“委托”掏出来吧!委托上面的说的是:把方法当做方法的参数,大概就是这个样子public void HelloWorld(string name, 方法 方法名)
上委托,把上面代码改了:

private static delegate void HelloWorldDelete(string name)
public void HelloWorld(string name, HelloWorldDelete chooseLanguage)
{
    chooseLanguage(name);
}
private static void ByEnglish(string name)
{
    Console.WriteLine("Hello World By" + name);
}
private static void ByChinese(string name)
{
    Console.WriteLine("你好,世界!作者:" + name);
}
static void Main(string[] args)
{
    HelloWorld("张三",ByChinese);
    HelloWorld("ZhangThree",ByEnglish);
}

输出:

你好,世界!作者:张三
Hello World By ZhangThree

再写个绑定版的(这回只写Main中的,因为其他的没变):

static void Main(string[] args)
{
    HelloWorldDelete delegateEnglish,delegateChinese;
    delegateEnglish = ByEnglish;
    delegateChinese = ByChinese;
    HelloWorld("张三",delegateChinese);
    HelloWorld("ZhangThree",delegateEnglish);
}

输出不变。
换个姿势绑定(只写Main中的,因为其他的没变):

static void Main(string[] args)
{    
    HelloWorldDelete delegateAll;
    delegateAll = ByEnglish;
    delegateAll += ByChinese;
    HelloWorld("张三", delegateAll );
}

输出:

Hello World By 张三
你好,世界!作者:张三

再换个体位(只写Main中的,因为其他的没变):

static void Main(string[] args)
{    
    HelloWorldDelete delegateAll;
    delegateAll = ByEnglish;
    //“=”表示赋值
    delegateAll += ByChinese;   //“+=”表示绑定,委托不能一开始直接+=,会出现“未赋值              
					//什么的错误”;相应的“-=”表示解除绑定
    delegateAll ("张三");
}

事件

写代码讲究个“说学逗唱”,说错了,讲究个“面向对象”。面向对象:封装、继承、多态。咱们就先从封装开始:
把上面的封装一下

public delegate void HelloWorldDelegate(string name);
public class HelloWorldClass
{
    HelloWorldDelegate del;
    public void HelloWorld(string name)
    {
        if(del != null)    //有方法注册了
            del(name);     //委托调用所有注册的方法
    }
}

class Program
{
    private static void ByEnglish(string name)
    {
        Console.WriteLine("Hello World By" + name);
    }
    private static void ByChinese(string name)
    {
        Console.WriteLine("你好,世界!作者:" + name);
    }

    static void Main(string[] args)
    {
        HelloWorldClass hw = new HelloWorldClass();
        hw.del = ByEnglish;
        hw.del += ByChinese;
        hw.HelloWorld("张三");
    }
}

输出:

Hello World By 张三
你好,世界!作者:张三

可是我们回头一看,HelloWorldClass里面的东西根本没封装住,很明显del暴露了,不想暴露就得改成private,改了以后几乎就没用了。然后,我们很自然想到private字段、public属性,例如

public class Number
{
    private int num;
    public int Num
    {
        get { return; }
        set { num = value; }
    }
}

所以,把“事件”掏出来:事件:事件之于委托,类似于属性之于字段。不管事件声明成public还是protected,委托都已经被事件封装成了private的。修改上面代码

public delegate void HelloWorldDelegate(string name);
public class HelloWorldClass
{
    public event HelloWorldDelegate del;
    public void HelloWorld(string name)
    {
        del(name);     //委托调用所有注册的方法
    }
}

class Program
{
    private static void ByEnglish(string name)
    {
        Console.WriteLine("Hello World By" + name);
    }
    private static void ByChinese(string name)
    {
        Console.WriteLine("你好,世界!作者:" + name);
    }

    static void Main(string[] args)
    {
        HelloWorldClass hw = new HelloWorldClass();
        hw.del = ByEnglish;    //会出现编译错误
        hw.del += ByChinese;   //直接+=就好  
        hw.HelloWorld("张三");
    }
}

输出:

你好,世界!作者:张三

其他学习途径

NGUI源码的EventDelegate类:
Delegate callback that Unity can serialize and set via Inspector.
可序列化、通过反射调用委托
[SerializeField]可序列化字段:mTarget、mMethodName、mParameters
UICamera事件响应后通过gameObject.SendMessage(funcName, …)调用相应组件(如:UIButton)中的相应函数(如:OnClick,然后OnClick会调用EventDelegate.Execute(onClick); onClick为之前设置的List<EventDelegate>)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#中委托和事件的区别 的相关文章

  • 自制Pixhawk飞控板烧写BootLoader教程

    对于自己制作的飞控板 xff0c 通过USB连接电脑之后 xff0c 开始电脑是无法检测到飞控板的端口存在的 检测不到端口 xff0c 就不能用控制台给飞控板烧写固件 xff0c 就不能用QGroundControl xff0c 就不能进行
  • Pixhawk原生固件PX4之常用函数解读

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a PX4Firmware 经常有人将Pixhawk PX4 APM还有ArduPilot弄混 这里首先还是简要说明一下 xff1a Pixhawk是飞控硬件平台 xff
  • Pixhawk原生固件PX4之添加uORB主题

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 本说明针对 Firmware v1 5 4 1 添加流程说明 1 在Firmware msg下新建uORB的成员变量 xff0c eg xxx msg 2 在Firm
  • Pixhawk原生固件PX4之SITL软件在环仿真

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 故事开始之前 xff0c 先按照笔者的这一篇博客在Ubuntu上完成固件的编译 jMAVSim仿真 jMAVSim仿真不需要任何配置 xff0c 直接输入指令即可 s
  • Pixhawk原生固件PX4之串口读取信息

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 这篇博客纯粹出于对FreeApe这位先行者贡献的复现 xff0c 也是本人一直想要进行的一项操作 在此还是做一下记录 时代在改变 xff0c 代码在更新 xff0c
  • Effective Modern C++ 条款21 比起直接使用new,更偏爱使用std::make_unique和std::make_shared

    比起直接使用new xff0c 更偏爱使用std make unique和std make shared 让我们从std make unique和std make shared之间的比较开始讲起吧 std make shared是C 43
  • Pixhawk原生固件PX4之串口添加读取传感器实现

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 本博客承接前一篇 xff0c 对FreeApe的串口添加超声波传感器博文后半部分进行学习 为什么叫前奏呢 xff0c 因为用了伪传感器 xff0c 把单片机用串口发送
  • Pixhawk原生固件PX4之MAVLink协议解析

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a PX4 对Mavlink 协议提供了良好的原生支持 该协议既可以用于地面站 Ground ControlStation GCS 对无人机 UAV 的控制 xff0c
  • Pixhawk原生固件PX4之TAKEOFF的启动流程

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 以TAKEOFF为例说明PX4中一个飞行模式的启动流程 众所周知由遥控器或者地面站决定Main state作为用户期望到达的飞行模式然后有commander进行条件判
  • Pixhawk原生固件PX4之驱动ID

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 驱动ID PX4使用驱动ID将独立传感器贯穿于整个系统 这些ID存储于配置参数中 xff0c 用于匹配传感器校正值 xff0c 以及决定哪些传感器被记录到log中 传
  • Pixhawk原生固件PX4之SPI驱动注册过程

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 一切事出有因 xff0c 为了添加一个自定义SPI总线连接的传感器 xff0c 首先要弄清楚一个SPI设备的注册过程 xff0c 大致涉及以下的一些文件 接下来就该以
  • Pixhawk原生固件PX4之MPU6000驱动分析

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 要想自己添加一个传感器的话 xff0c 最好先搞明白已有的传感器的工作过程 这里记录一下PX4中MPU6000加速度计陀螺仪的解读过程 xff0c 从mpu6000
  • Pixhawk原生固件PX4之日期时间的确定

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 偶然注意到PX4日志中老是出现类似于2000 01 01 00 00 00这种日期 有兴趣的可以搜索一下千年虫问题 xff0c 于是结合代码进行了一波分析 最后定位到
  • Pixhawk原生固件PX4之添外置传感器MPU6500

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 成功的在Pixhawk上添加了一个自定义的传感器MPU6500 Pixhawk飞控板上空余出一个SPI4接口 提示 xff1a 多出来的GPIO EXT引脚可以作为片
  • 多旋翼无人机进阶教程

    无人机是一个系统的工程 xff0c 不可谓不庞大 开源飞控盛行 xff0c 重复造轮子的工作实在无需再做 但是若决定真正的去研究飞控 xff0c 必须从本质出发 xff0c 熟悉并了解其实现原理 纷繁复杂的资料 xff0c 让人无法分辨 笔
  • Pixhawk原生固件PX4之MAVLink外部通讯

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 目前的需求是 xff1a 一台电脑连数传 xff0c Pixhawk飞控上电连数传 xff0c 电脑向Pixhawk发送MAVlink消息 至少有5种方案 xff1a
  • rtsp流浏览器播放方案

    rtsp流在主流浏览器并不支持直接播放 比如大华的视频流 xff1a rtsp admin 123456 64 192 168 10 129 cam realmonitor channel 61 1 amp subtype 61 0 xff
  • PX4开发指南中文版维护说明

    PX4中文维基现已与PX4开发者官网合并 现在大家可以直接进入官网进行语言切换 PX4中文版的维护依然需要你的贡献 贡献说明 xff1a 官方的GitHub仓库为https github com PX4 Devguide 我将其Fork后的
  • OpenCV图像坐标系与行列宽高的关系

    刚开始接触图像处理 xff0c 关于图像坐标系与行列宽高的关系感到纠结 xff0c 但是似乎没有更好的处理方法了 xff0c 其对应关系大致如下 row 61 61 height 61 61 Point y col 61 61 width

随机推荐

  • Pixhawk原生固件PX4之位姿控制算法解读

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 参考文献 xff1a Minimum Snap Trajectory Generation and Control for Quadrotors PX4中多旋翼无人机
  • Pixhawk精准着陆之IRLock配置

    安装说明 下载Pixymon和pixy对应markone的固件 xff0c 在这里 固件必须是firmware IRLOCKpixy 1 0 1 hex irlock 61 markone 然后固件里 irlock 61 pixy 给Pix
  • Pixhawk原生固件PX4之offboard

    offboard PX4中的offboard 暂译作外部控制 是一个非常强大的功能 可以接受来自外部的控制指令 xff0c 按照目前的了解来看 xff0c offboard搭配上MAVROS以及类似于TX1 NUC板载计算器 xff0c 在
  • 相机标定原理

    cnblogs上的这篇讲相机标定的博文值得一看 csdn上这篇也可以参考 相机标定基础知识 相机标定技术涉及到一些数学原理和几何模型 xff0c 这些数学原理和几何模型是相机标定算法使用和进一步发展的基础 下面对相机标定技术中涉及到的齐次坐
  • VS Code的Git插件

    Visual Studio Code是微软公司推出的一款跨平台代码编辑 Edit 编译 Build 调试 Debug 工具 笔者认为其相当于是Sublime Text这款代码编辑器的升级版 集成了丰富的插件 xff0c 包括代码管理中极为常
  • Ubuntu缺少libncurses.so.5的解决办法

    执行arm none eabi gdb时候出错 xff1a arm none eabi gdb error while loading shared libraries libncurses so 5 cannot open shared
  • freeRTOS的任务抢占和时间片轮转

    实时操作系统的一个特点就是可以任务抢占 xff0c 高优先级的任务可以抢占比自己优先级低的任务 xff0c 如果新任务优先级和当前人任务优先级一样 xff0c 且在使能了时间片的方式的话 xff0c 二者以时间片的方式共享cpu xff0c
  • RH850 F1L freeRTOS 任务栈的切换

    pxCurrentTCB指向的任务块中 xff0c 有2个和栈相关的变量pxTopOfStack和pxStack pxTopOfStack指向当前堆栈栈顶 xff0c 随着进栈出栈 xff0c pxTopOfStack指向的位置是会变化的
  • opencv 3.0 图像去畸变 undistortion

    主要用到的是 initUndistortRectif yMap这个函数 在opencv中这个函数是用于 去除镜头畸变的图像拉伸 为了快速算法 xff1a 使用了坐标查找变和双线性差值的方法 先上结果图 原图 去畸变至全图 去畸变并保留最大图
  • 多传感器融合MSF算法源码阅读(三)

    文章目录 1 触发测量更新回调函数2 测量更新状态量3 总结 无人驾驶算法学习 xff08 六 xff09 xff1a 多传感器融合MSF算法 多传感器融合MSF算法源码阅读 一 多传感器融合MSF算法源码阅读 二 1 触发测量更新回调函数
  • 视觉VIO:S-MSCKF算法学习(一)

    文章目录 1 算法简介2 算法调试3 代码解读3 1 前端 ImageProcessor3 2 后端 Msckf Vio 1 算法简介 Mingyang Li博士于2007年提出MSCKF Multi State Constraint Ka
  • 无人驾驶算法学习(六):多传感器融合MSF算法

    文章目录 1 引言2 算法理论2 1 MSF基本模型2 2 预测2 3 测量与更新 3 核心代码分析4 代码实战 1 引言 本文的多传感器融合是建立在读懂 Quaternion kinematics for the error state
  • 多传感器融合MSF算法源码阅读(一)

    文章目录 1 代码框架1 1代码调用关系图 1 2主要函数调用关系图 2 posemsf阅读2 1程序入口 xff1a 2 2PoseSensorManager类 1 代码框架 论文解读 无人驾驶算法学习 xff08 六 xff09 xff
  • 通过launch文件修改订阅话题的两个操作

    文章目录 1 引言2 利用param修改话题2 利用remap修改话题 1 引言 在调试程序中需要经常修改订阅的话题 如果直接修改每次都要编译 在大型项目中这是难以想象的 所以利用launch中的param机制 通过修改launch文件进行
  • ubuntu下安装vnc出错(灰屏)

    我 win10 用的 vncviewer exe xff0c 在Ubuntu上首先需要安装vnc4server apt get install vnc4server 出现灰色屏幕和 型鼠标是因为vncserver找不到指定的图形化组件 xf
  • 51UWB单片机连接ESP8266实现Wifi接收串口数据

    UWB定位需要电脑读取UWB基站的串口数据来读取距离信息 xff0c 用wifi连接可以实现远程接收串口数据方便连接 这里记录一下如何让51UWB单片机接入WiFi模块ESP8266 前置条件 xff1a 单片机完成基站 xff08 RX
  • Qt中的三种基类

    一 QMainWindow xff1a QMainWindow类提供一个带有菜单条 xff0c 工具条和一个状态条的主应用程序窗口 主窗口通常提供一个大的中央窗口部件 xff0c 以及周围菜单 xff0c 工具条 xff0c 和一个状态栏
  • 如何理解强化学习中迭代线性-二次型调节器(ILQR)算法

    1 强化学习预备知识 xff08 1 xff09 状态 动作价值函数Q s a xff1a 在状态s xff0c 先立即执行动作a xff0c 后面所有的状态都按照最优动作进行执行 xff0c 所能获得价值之和 xff1b xff08 2
  • 字符串中字符查找函数:strchr,wcschr 及strrchr, wcsrchr函数

    xff08 1 xff09 char strchr const char string int c wchar t wcschr const wchar t string wchar t c Find a character in a st
  • C#中委托和事件的区别

    言简意赅的解释 先说总结 xff1a 事件就是委托链 xff08 也就是继承自MulticastDelegate类的委托 xff0c 用delegate声明的委托就是继承自MulticastDelegate类的 xff09 的属性 xff0