C#——Delegate(委托)与Event(事件)

C#——Delegate(委托)与Event(事件)

  • 前言
  • 一、Delegate(委托)
    • 1.是什么?
    • 2.怎么用?
      • Example 1:无输入无返回值
      • Example 2:有输入
      • Example 3:有返回值
      • Example 4:多播委托
      • Example 5:处理有返回值的多播委托的结果
  • 二、Event(事件)
    • 1.是什么?
    • 2.怎么用?
      • Example 1:简单案例
      • Example 2:流程中重复绑定同一方法的优化
  • 三、总结


前言

在刚开始学习C#的时候,常常委托与事件傻傻分不清,经常性的混为一谈。他们功能相似,应用场景却不太一样,下面就从分别的介绍再到差异的分析一起来看看啪。

一、Delegate(委托)

1.是什么?

委托是 C# 中的一种类型,它代表了对一个或多个方法的引用。它类似于函数指针,在编程中可以将方法作为参数传递给其他方法。

2.怎么用?

看个简单的委托应用:

例子是基于C#控制台编写的

Example 1:无输入无返回值

申明委托类型:

delegate void write();

定义一个委托变量:

        static write w;

写一个和申明的委托变量相同输入输出类型的函数:

        public static void writeS()
        {
            Console.WriteLine(1);
        }

给委托绑定方法并调用:

        static void Main(string[] args)
        {
            w += writeS;  //绑定
            w();		  //调用,会运行绑定的方法(writeS)
            Console.ReadKey();
        }

结果:
直接打印一个1。
在这里插入图片描述

Example 2:有输入

申明委托类型:

delegate void write(int a,int b);

定义一个委托变量:

        static write w;

写一个和申明的委托变量相同输入输出类型的函数:

        public static void writeS(int a,int b)
        {
            Console.WriteLine(a + b);
        }

给委托绑定方法并调用:

        static void Main(string[] args)
        {
            w += writeS;  //绑定
            w(1,2);		  //调用,会运行绑定的方法(writeS)
            Console.ReadKey();
        }

结果:
直接打印一个3。
在这里插入图片描述

Example 3:有返回值

申明委托类型:

delegate bool write(int a,int b);

定义一个委托变量:

        static write w;

写一个和申明的委托变量相同输入输出类型的函数:

        public static bool writeS(int a,int b)
        {
            return a > b;
        }

给委托绑定方法并调用:

        static void Main(string[] args)
        {
            w += writeS;  //绑定
            Console.WriteLine( w(1,2));		  //调用,会运行绑定的方法(writeS)
            Console.ReadKey();
        }

结果:
直接打印一个False。
在这里插入图片描述

Example 4:多播委托

在此讨论比较特殊的有返回值的多播委托
简单理解,就是把多个方法绑定到一个委托,委托触发将触发所有绑定的方法。

申明委托类型:

delegate bool write(int a,int b);

定义一个委托变量:

        static write w;

写一个和申明的委托变量相同输入输出类型的函数:

        public static bool writeS(int a,int b)
        {
            return a > b;
        }
        
        public static bool writeS2(int a,int b)
        {
            return a < b;
        }

给委托绑定方法并调用:

        static void Main(string[] args)
        {
            w += writeS;  //绑定
            w += writeS2;  //绑定
            Console.WriteLine( w(1,2));		  //调用,会运行绑定的方法(writeS和writeS2)
            Console.ReadKey();
        }

结果:
直接打印一个True。
在这里插入图片描述

此时可以注意到,我绑定了两个带返回值的方法,第一个(writeS)返回false,第二个(writeS2)返回true。实际页面打印的是True。多次测试后可以发现,当多播委托带有返回值时且有多个绑定方法时,返回值将以最后一个添加绑定的为最终结果。

Example 5:处理有返回值的多播委托的结果

为解决Example4中绑定多个返回值的方法时,可以在外部进行数据分析来获取最终的结果。

新增代码如下:

        static bool JudgeRet(int a,int b)
        {
            bool ret = true;
            if (w != null)
            {
                foreach (write item in w.GetInvocationList())//变量委托里面的所有绑定的方法列表,获取结果并处理结果
                {
                    ret = ret & item(a,b);//处理流程,有false就为false。
                }
            }
            return ret;
        }

完整代码如下:

    class Program
    {
        delegate bool write(int a,int b);
        static write w;
        static void Main(string[] args)
        {
            w += writeS;
            w += writeS2;
            Console.WriteLine(JudgeRet(1,2));
            Console.ReadKey();
        }

        static bool JudgeRet(int a,int b)
        {
            bool ret = true;
            if (w != null)
            {
                foreach (write item in w.GetInvocationList())
                {
                    ret = ret & item(a,b);
                }
            }
            return ret;
        }

        public static bool writeS(int a,int b)
        {
            return a > b;
        }

        public static bool writeS2(int a, int b)
        {
            return a < b;
        }
    }

结果:
有false则为false。
在这里插入图片描述

二、Event(事件)

1.是什么?

事件是一种特殊类型的委托,用于实现观察者模式。它限制了委托的使用,只允许外部类通过 += 和 -= 运算符订阅和取消订阅事件。它提供了一种安全的订阅机制,防止外部类直接调用委托列表。只有持有类可以触发事件。

本质上:事件是对委托的封装,提供了一种更安全、更封装的方式来进行观察者模式的实现。

2.怎么用?

Example 1:简单案例

全部代码以及解析:

    public delegate bool write(int a, int b);  //定义的委托类型

    public class test							//测试类,体现事件只能在持有类中触发
    {
        write w;								//委托对象

        public event write WriteEvent;			//事件对象
        
        public void triger(int a, int b)		//触发事件
        {
            WriteEvent?.Invoke(a, b);			//判断事件是否为空,不为空则触发
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            test t = new test();				//生成测试类实例
            //此时在外部,无法访问到委托实例w,只能通过事件WriteEvent绑定
            t.WriteEvent += writeS;				//绑定方法
            t.WriteEvent += writeS;
            t.WriteEvent += writeS;				//绑定了多次相同的方法
            t.WriteEvent += writeS;

            t.triger(1, 2);						//触发

            Console.ReadKey();
        }

        public static bool writeS(int a, int b)
        {
            Console.WriteLine(a + b);
            return a > b;
        }
    }

结果如下:

发现多次绑定同一方法时,无法判断重复,绑定几次执行几次。
在这里插入图片描述

上文需要注意的是,WriteEvent?.Invoke(a, b);直接调用了事件名,在简略声明中,可以 使用Invoke调用事件,但也仅限于事件拥有类内部使用。

Example 2:流程中重复绑定同一方法的优化

优化事件代码如下:

    public delegate bool write(int a, int b);

    public class test
    {
        write w;

        public event write WriteEvent
        {
            add
            {
                if (w != null && w.GetInvocationList().Contains(value))
                {
                    return;
                }
                w += value;
            }
            remove
            {
                w -= value;
            }
        }

        public void triger(int a, int b)
        {
            w(a, b);							//此处因为重写了Add以及Remove无法使用WriteEvent?.Invoke(a, b);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            test t = new test();
            t.WriteEvent += writeS;
            t.WriteEvent += writeS;
            t.WriteEvent += writeS;
            t.WriteEvent += writeS;
            t.triger(1, 2);
            Console.ReadKey();
        }

        public static bool writeS(int a, int b)
        {
            Console.WriteLine(a + b);
            return a > b;
        }
    }

结果:
在这里插入图片描述

三、总结

简单点:

  • 委托允许你将方法作为参数传递或存储,可以被直接调用。
  • 事件是一种特殊类型的委托,提供更安全、封装的订阅机制,只允许持有类触发事件(且必须是简单声明)。

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

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

相关文章

抖音外卖商品模型

目录 一、抖音外卖商品模型 二、商家运营流程 &#xff08;一&#xff09;商家入驻流程 &#xff08;二&#xff09;商品发布流程 三、推广带货流程 &#xff08;一&#xff09;短视频带货 &#xff08;二&#xff09;直播视频带货 【直播工具】 【直播流程】 直播前…

SQL Server 数据库,创建数据表(使用T-SQL语句)

2.3表的基本概念 表是包含数据库中所有数据的数据库对象。数据在表中的组织方式与在电子表格中相似&#xff0c;都是 按行和列的格式组织的&#xff0c;每行代表一条唯一的记录&#xff0c;每列代表记录中的一个字段.例如&#xff0c;在包含公 司员工信息的表中&#xff0c;每行…

数据结构:图文详解双向链表的各种操作(头插法,尾插法,任意位置插入,查询节点,删除节点,求链表的长度... ...)

目录 一.双向链表的概念 二.双向链表的数据结构 三.双向链表的实现 节点的插入 头插法 尾插法 任意位置插入 节点的删除 删除链表中第一次出现的目标节点 删除链表中所有与关键字相同的节点 节点的查找 链表的清空 链表的长度 四.模拟实现链表的完整代码 前言&am…

初探Java之旅:探寻Java的奥秘

✨个人主页&#xff1a;全栈程序猿的CSDN博客 &#x1f4a8;系列专栏&#xff1a;Java从入门到精通 ✌座右铭&#xff1a;编码如诗&#xff0c;Bug似流星&#xff0c;持续追求优雅的代码&#xff0c;解决问题如同星辰般自如 在计算机编程的世界中&#xff0c;有一门被誉为“千变…

位图布隆过滤器(附面试题)

文章目录 目录 文章目录 前言 一 . 位图 1.1 面试题 1.2 位图概念 1.3 位图的实现 1.4 位图的应用 二 . 布隆过滤器 2.1 布隆过滤器提出 2.2布隆过滤器概念 2.3 布隆过滤器的查找 2.4 实现 2.5 布隆过滤器删除 2.6 布隆过滤器优点 2.7 布隆过滤器缺陷 2.8 布隆过滤器使用场景 三…

面试官:说说Vue中Proxy与Object.defineProperty的用法与区别

前言 面试时&#xff0c;我们说完Vue响应式原理&#xff0c;或者Vue2和Vue3的区别时&#xff0c;通常会引出Vue3使用了Proxy来优化响应式&#xff0c;而面试官会继续深挖&#xff1a;说说Proxy与Object.defineProperty的区别。 我们不能只说Proxy直接代理一个对象&#xff0c…

【java毕业设计源码】基于SSM框架的在线智能题库管理系统设计与实现

该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等学习内容。 目录 一、项目介绍&#xff1a; 二、文档学习资料&#xff1a; 三、模块截图&#xff1a; 四、开发技术与运行环境&#xff1a; 五、代码展示&#xff1a; 六、数据库表截图&#xff1a…

【论文阅读 + 核心代码定位解读】(2023 AAAI)HiCLR

Hierarchical Consistent Contrastive Learning for Skeleton-Based Action Recognition with Growing Augmentations Contribution 直接使用 strong augmentations 会导致图片/骨架点序列的结构变形和语义信息损失&#xff0c;从而导致训练过程的不稳定。于是本文提出了一种逐…

Java Servlet

请求 请求行 方式 uri http/1.1 请求头 请求体 form表单标签提交Get请求时&#xff0c;参数以键值对形式放在url后&#xff0c;不放在请求体里&#xff0c;Get方式的请求也是可以有请求体的 Post请求时&#xff0c;放在请求头里面 Servlet (server applet) 是运行在服务端…

curl --compressed报错,此版本不支持此命令

出现这个问题是因为微软windows自带的curl不支持这个选项,验证如下 执行where curl 时,可以看到输出为 C:\Windows\System32\curl.ee 解决方法是使用其它curl,下载地址如下 curl for Windows https://curl.se/windows/ 然后把安装目录的bin目录放到path环境变量里最开始, 让…

基于微信小程序的高校活动系统

1 前言 1.1开发背景及意义 高校课余活动管理是中职学生素质教育的重要途径及有效方式&#xff0c;特别是对于一个院校的校园文化建设、校风学风建设和学生综合素质方面的提高至关重要t叫"。良好的学生活动组织可以更好地调动学生参与活动&#xff0c;让学生展示自己的能力…

理解SpringIOC和DI第一课(Spring的特点),IOC对应五大注解,ApplicationContext vs BeanFactory

Spring是一个包含众多工具等Ioc容器 对象这个词在Spring范围内&#xff0c;称为bean Spring两大核心思想 1.IOC (IOC是控制反转&#xff0c;意思是控制权反转-控制权&#xff08;正常是谁用这个对象&#xff0c;谁去创建&#xff0c;&#xff09;-控制对象的控制权&#xf…

十五届海峡两岸电视主持新秀大会竞赛流程

海峡两岸电视主持新秀会是两岸电视媒体共同举办的一项活动&#xff0c;旨在为两岸年轻的电视主持人提供一个展示才华的舞台&#xff0c;促进两岸文化交流和青年交流。本届新秀会是第十二届海峡两岸电视艺术节的重要活动之一。本次竞赛赛制流程如下&#xff1a; &#xff08;1&…

navicat某些表为什么不按主键排序

不知道大家注没注意过navicat的这种情况 为什么不是按主键排序呢 我们来全表扫描看下他的执行计划 explain select * from orsql3; 可以发现不是全表扫描而是索引树扫描&#xff0c;由此得知了共性&#xff0c;不按主键顺序排序的表&#xff0c;肯定是在二级索引上就保存着全部…

【uni-app】赋予你的APP(Android原生)小程序开发能力

采用DCloud(数字天堂&#xff08;北京&#xff09;网络技术有限公司)的uniMPsdk(uni小程序SDK)&#xff0c;是为原生App打造的可运行基于 uni-app 开发的小程序前端项目的框架&#xff0c;从而帮助原生App快速获取小程序的能力。 uni-app文档地址(小程序开发人员开发用) uniMP…

SmartsoftHelp8,条形码,二维码 生成,解析 专业工具

生成条形码 生成二维码 条形码解析 二维码解析 专业工具 下载地址&#xff1a; https://pan.baidu.com/s/1zBgeYsqWnSlNgiKPR2lUYg?pwd8888

9、Qt使用随机验证码

一、新建项目 创建一个"Qt Widget Application"项目&#xff0c;基类选择“QMainWindow” 二、自定义CaptchaLabel类 右击项目名&#xff0c;选择"Add New...” C -> CClass&#xff0c;点击“Choose” 更改类名CaptchaLabel&#xff0c;添加基类QLabel&a…

《YOLOv8原创自研》专栏介绍 CSDN独家改进创新实战专栏目录

YOLOv8原创自研 https://blog.csdn.net/m0_63774211/category_12511737.html?spm1001.2014.3001.5482 &#x1f4a1;&#x1f4a1;&#x1f4a1;全网独家首发创新&#xff08;原创&#xff09;&#xff0c;适合paper &#xff01;&#xff01;&#xff01; &#x1f4a1;&a…

分治-归并排序

文章目录 &#x1f31e;315. 计算右侧小于当前元素的个数&#x1f308;1. 题目⛅2. 算法原理&#x1fa90;3. 代码实现 &#x1f315;493. 翻转对&#x1f320;1. 题目⭐2. 算法原理&#x1f31f;3. 代码实现 &#x1f31e;315. 计算右侧小于当前元素的个数 &#x1f308;1. 题…

Matlab数学建模详解之发电机的最佳调度实现

&#x1f517; 运行环境&#xff1a;Matlab、Python &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&am…