C#中委托与事件

一、委托

1.1概念

委托是一种引用类型,它可以用于封装并传递方法作为参数。委托可以理解为是一个指向方法的**“指针”,它允许将方法作为参数传递给其他方法或存储在数据结构中,然后稍后调用这些方法。(委托可以看作时函数的容器)**

1.2目的作用

委托的目的就是将方法当作参数进行传递 ;
封装变化的请求

1.3定义

  1. 委托:将方法作为参数进行传递 方法是有签名( 签名:返回值类型 ,参数列表(参数的个数 ,参数类型))。
  2. 委托需要和方法有相同的签名 也就是说委托和方法 要参数相同 返回值相同 你才可以引用这个方法。
  3. 访问修饰符:public protected internal…委托的访问修饰符一般都定义成public,因为我们的程序可能会涉及到跨程序集调用。
  4. 委托和类是平级的 不要定义在类里面
//01定义委托public delegate void DelTest();internal class Program{static void Main(string[] args){       //03.创建委托对象,两种方式DelTest delTest = new DelTest(Test);//或者 创建委托变量可以省略new 关键字,直接将要传递的方法赋值即可,注意,方法在赋值的时候,不要写();//虽然我们没有创建委托对象(new出来的才叫对象),但是编译器在编译代码的是很好还是去帮助我们new了委托对象DelTest delTest1 = Test;//04.调用委托,两种方式:委托名字();或者委托名字.Invoke();delTest();delTest.Invoke();//调用(委托)对象里面存在的方法// delTest1();}//02.定义方法public static void Test(){Console.WriteLine("没有参数没有返回值");}}
}

1.4匿名方法创建委托

  1. 当使用的方法只使用一次时,没必要单独创建一个方法,直接定义委托对象时创建匿名方法
DelTest delTest = delegate () { Console.WriteLine("没有返回值没有参数"); };//后面加封号
delTest();
  1. 匿名方法允许你在需要委托的地方直接定义方法体,而不需要显式地创建一个单独的方法。
//没有参数 没有返回值
DelTest1 delTest1 = delegate () { Console.WriteLine("没有参数 没有返回值"); };
delTest1();//没有参数  有返回值
DelTest2 delTest2 = delegate () { return "没有参数  有返回值"; };
Console.WriteLine(delTest2());//有参数 没有返回值
DelTest3 delTest3 = delegate (string str) { Console.WriteLine("有参数 没有返回值"+str); };
delTest3("delTest3");//有参数  有返回值
DelTest4 delTest4 = delegate (int n1,int n2) { return n1 + n2; };
Console.WriteLine(delTest4(10,20));//没有参数 没有返回值
public delegate void DelTest1();
//没有参数  有返回值
public delegate string DelTest2();
//有参数 没有返回值
public delegate void DelTest3(string name);
//有参数  有返回值
public delegate int DelTest4(int n1,int n2);

1.5委托+Lambda方式简化创建(常用)

  1. Lambda格式
(parameters) => expression

其中,parameters是传递给委托的参数列表,可以是空的或包含多个参数;expression是一个表达式,它将计算并返回给委托调用者的值。
2. 创建委托:匿名函数+Lambda+委托

1.没有参数 没有返回值
1.1匿名方法
DelTest1 delTest1 = delegate () { Console.WriteLine("没有参数 没有返回值"); };
delTest1();1.2lambda1
DelTest1 delTest11 = () => { Console.WriteLine("没有参数 没有返回值"); };
delTest11();
  1. 图中箭头指向的地方对应位置作用一样
    在这里插入图片描述
2.有参数 没有返回值DelTest3 delTest3 = delegate (string name) { Console.WriteLine(name); };
delTest3("有参数 没有返回值");DelTest3 delTest31 = (name) => { Console.WriteLine(name); };当你是一个参数的时候可以去掉()  但是你没有参数列表的时候需要加上()
DelTest3 delTest32 = name => { Console.WriteLine(name); };
delTest31("有参数 没有返回值");

1.6Action/Func创建委托

Action委托本身不包含返回值,主要封装那些没有返回结果的函数。Func委托则可用于需要返回值的情况。

//00、自己定义的泛型委托
DelTest4<int> delTest4 = n1 => { Console.WriteLine(n1); };
delTest4(230);
泛型委托
public delegate void DelTest4<T>(T t);//01、 Action
//Action就是系统帮我们定义好的一个没有参数没有返回值的委托
//委托 没有参数没有返回值 直接使用 不需要再去定义一个委托 
Action action = () => { Console.WriteLine("a"); };
//调用内置委托和调用普通委托一样
action();//TResult 代表返回值的类型
//第一个int 表示参数一为int类型
//第二个int 表示参数二为int类型
//第三个int 表示参数三为int类型
//第四个string 表示参数四为返回值为string
//最后一个永远是返回值
Func<int, int, int,string> func = (n1, n2,n3) => { return "张三的成绩为"+n1+n2+n3; };
Console.WriteLine(func(100, 200,300)); 

1.7多播委托

多播委托时为了让同一个委托对象,一行调用多个方法同时执行,如游戏中,一个人物按下开火键(委托对象),手中的冲锋枪和步枪同时开火,如果不使用多播委托,需要先进行武器切换选择其中一个进行开火。

Action action = M1;
//如果使用 多播委托 必须在调用之前进行绑定//多播委托和字符串拼接类似 每拼接一次 在实际的内存中 都会创建一个新的委托对象
//我们看到的是一个委托对象指向了多个方法
//实际上每次拼接后 创建出来新的对象结果action += M2;
action += M3;
action += M4;
action += M5;//从结果来看 多播委托的调用是顺序的 ,但是不代表多播委托 的调用就是顺序的 微软随时可以改变顺序//使用队列action();static void M1()
{Console.WriteLine("我是第1个方法");
}
static void M2()
{Console.WriteLine("我是第2个方法");
}
static void M3()
{Console.WriteLine("我是第3个方法");
}
static void M4()
{Console.WriteLine("我是第4个方法");
}
static void M5()
{Console.WriteLine("我是第5个方法");
}

1.8委托注意事项

委托不能为空,为空的委托不能调用,报错;
在这里插入图片描述
空委托不能调用,所以使用委托前要进行判断:

if(attack!=null)
{attack();//调用委托
}

上面的方式过于繁琐,可以简化:

//无参数
attack?.Invoke();
//有参数
attack?.Invoke(a,b);

二、事件

1.概念

C#中的事件是一种特别的委托,它可以被多个方法订阅,并且在特定情况下触发这些方法的执行。

2.使用

2.1事件的定义

  1. 声明事件:在C#中,事件通常通过event关键字声明。它定义了一个可以由多个方法订阅的特殊类型的委托。例如,声明一个没有返回值且不带参数的事件:public event Action MyEvent;。
  2. 委托类型:事件的背后是一个委托类型,它定义了订阅事件的方法的签名。例如,使用内置的Action委托或自定义委托来定义事件。
  3. 访问修饰符:事件的声明可以包含访问修饰符,如public或private,以控制对事件的访问级别。

2.2事件的订阅

  1. 订阅事件:订阅事件是通过+=运算符完成的。例如,myObject.MyEvent += MyMethod;,其中MyMethod是响应事件的方法。
  2. 触发事件:当特定条件满足时,事件会被触发。这通常是在类的内部,通过EventName?.Invoke()形式调用。例如,MyEvent?.Invoke();会触发所有订阅了MyEvent的方法。
  3. 取消订阅:使用-=运算符可以取消事件订阅,如myObject.MyEvent -= MyMethod;

3.案例

委托会遇到的问题
//问题1:我们通过委托来实现事件 由于委托在定义的时候,一般都定义成public 这样就导致了 用户端 不给委托赋值的情况了,也可以直接调用
//问题2:由于委托本质上就是一个数据类型 所以如果赋值为null的话 就会把之前的值覆盖掉 变成一个null对象

//01、直接调用没赋值的委托,可以调用,但是这是不正确的
musicPlayer.BeforePlayMusic();
musicPlayer.AfterPlayMusic();
//02、直接调用事件
//外界不允许直接调用事件  因为事件的语法规定了这一点
musicPlayer.BeforePlayMusic();
musicPlayer.AfterPlayMusic();

//通过音乐播放器  讲解事件在程序中是啥//实例化音乐播放器类
MusicPlayer musicPlayer = new MusicPlayer();
musicPlayer.BeforePlayMusic += () => { Console.WriteLine("加载我们的歌词"); };
musicPlayer.AfterPlayMusic += () => { Console.WriteLine("跳转下一曲"); };musicPlayer.BeforePlayMusic += null;
musicPlayer.AfterPlayMusic += null;//用户单击了播放按钮
musicPlayer.StartMusic();
musicPlayer.EndMusic();//通俗的说:就是发生【某个变化】的是时候 触发某段代码
//没有用到事件---- - 没有发生变化
//需求1: 我希望在播放音乐之前 ,能够加载我们的歌词
//需求2:我希望播放音乐结束后 能够自动跳转下一曲
//需求应该交给用户 :委托
class MusicPlayer
{//01、声明两个事件public event Action BeforePlayMusic;public event Action AfterPlayMusic;//播放音乐  不能给别人调用private void MusicPlay(){//判断用户是否是会员//判断用户播放的音乐是否是会员音乐//去数据量里面加载音乐文件//开始播放.....//加载我们的歌词BeforePlayMusic();Console.WriteLine("音乐播放中");}//点击按钮播放音乐public void StartMusic(){this.MusicPlay();Thread.Sleep(2000);}public void EndMusic(){Console.WriteLine("音乐关闭中");AfterPlayMusic();//跳转下一曲}}

三、委托与事件区别

  1. 事件只能在类的内部进行触发,不能在类的外部进行触发。而委托在类的内部和外部都可触发;
  2. 事件是一个特殊的委托,查看反编译工具之后的代码,发现事件是一个 private 委托
    委托测试:
//03、触发类内部定义的委托
Test te = new Test();
te.SayHello();
//04在类外部进行委托对象赋值并处罚
Test.Foo fo= () => { Console.WriteLine("02、类外部触发的委托!"); };
fo();//创建类
class Test
{//01定义委托	public delegate void Foo();public void SayHello(){//02在类内部对委托对象进行赋值Foo fo=()=> { Console.WriteLine("01、类内部触发的委托!"); };fo();}}

在这里插入图片描述
事件测试:

//03实例化类并触发事件
Test te = new Test();
te.SayHello();class Test
{
//01、定义事件public event Foo  Foo1;public void SayHello(){//02、方法绑定Foo1+= () => { Console.WriteLine("类内部触发的事件!"); };Foo1();}}
//02类外部进行绑定方法,并触发
te.Foo1 += () => { Console.WriteLine("a2"); };
te.Foo1();class Test
{//01定义事件public event Foo  Foo1;
}

报错,事件无法在类的外部进行触发
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

汽车IVI中控开发入门及进阶(三十三):i.MX linux开发之开发板

前言: 大部分物料/芯片,不管MCU 还是SoC,都会有原厂提供配套开发板,有这样一个使用原型,在遇到问题时或者进行开发时可以使用。 i.MX 8QuadXPlus MEK board: 1、要测试display显示器,可使用i.MX mini SAS将“LVDS1_CH0”端口连接到LVDS到HDMI适配器的cable。 2、要测试…

Stream练习

运用点&#xff1a; 流内数据类型转换(map)、filter、limit、skip、concat(让两个流合并) 题目&#xff1a; 操作1、2&#xff1a; ArrayList<String> manList new ArrayList<>();ArrayList<String> womanList new ArrayList<>();Collections.addAl…

多模态MLLM都是怎么实现的(11)--从SadTalker到快手LivePortait

我之前出差带休假差不多两个礼拜吧&#xff0c;今天回北京更新一篇 我确实找到了一个有意思的东西&#xff0c;LivePortrait 这东西开源了&#xff0c;你可以认为是目前做得最好的"Sadtalker"&#xff0c;国内也有dream-talker&#xff0c;EMO之类的。 我之前看EMO的…

C++——模板详解(下篇)

一、非类型模板参数 模板参数分为类型形参与非类型形参。 类型形参即&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之后的参数类型名称。 非类型形参&#xff0c;就是用一个常量作为类&#xff08;函数&#xff09;模板的一个参数&#xff0c;在类&#…

kubernetes集群部署:node节点部署和CRI-O运行时安装(三)

关于CRI-O Kubernetes最初使用Docker作为默认的容器运行时。然而&#xff0c;随着Kubernetes的发展和OCI标准的确立&#xff0c;社区开始寻找更专门化的解决方案&#xff0c;以减少复杂性和提高性能。CRI-O的主要目标是提供一个轻量级的容器运行时&#xff0c;它可以直接运行O…

Docker学习笔记(三)Dockerfile

一、什么是Dockerfile Dockerfile 是一个用于自动化构建 Docker 镜像的文本文件&#xff0c;其中包含了从一个基础镜像开始&#xff0c;到最终形成所需定制镜像的所有指令集。这个文件中的每一条指令都对应着构建镜像过程中的一个步骤或一层&#xff0c;指导 Docker 如何安装软…

PHP智慧门店微信小程序系统源码

&#x1f50d;【引领未来零售新风尚】&#x1f50d; &#x1f680;升级启航&#xff0c;智慧零售新篇章&#x1f680; 告别传统门店的束缚&#xff0c;智慧门店v3微信小程序携带着前沿科技与人性化设计&#xff0c;正式启航&#xff01;这个版本不仅是对过往功能的全面优化&a…

从GREE格力看如何起全球商标名称!

有些主体需要走出去出口到国外&#xff0c;普推商标知产老杨看到在一些海外电商平台的出售产品&#xff0c;也会需要英文商标&#xff0c;有的会申请申请注册中英结合商标&#xff0c;在国外申请注册也是比较方便。 格力开始想用“GLEE”(快乐)这个词作为商标名称&#xff0c;但…

【JavaWeb程序设计】JSP编程II

目录 一、输入并运行下面的import_test.jsp页面 1.1 代码运行结果 1.2 修改编码之后的运行结果 二、errorPage属性和isErrorPage属性的使用 2.1 下面的hello.jsp页面执行时将抛出一个异常&#xff0c;它指定了错误处理页面为errorHandler.jsp。 2.1.2 运行截图 2.2 下面…

医疗器械FDA | FDA如何对医疗器械网络安全认证进行审查?

FDA医械网络安全文件出具​https://link.zhihu.com/?targethttps%3A//www.wanyun.cn/Support%3Fshare%3D24315_ea8a0e47-b38d-4cd6-8ed1-9e7711a8ad5e FDA对医疗器械的网络安全认证进行审查时&#xff0c;主要关注以下几个方面&#xff0c;以确保医疗器械在网络环境中的安全性…

2 极/2 零 (2P2Z) 补偿器

极/2 零 &#xff08;2P2Z&#xff09; 补偿器是模拟 II 型控制器的数字实现。它是一种滤波器&#xff0c;通过考虑两个极点和一个零点&#xff0c;将特定的增益和相位升压引入系统。您必须战略性地选择每个极点和零点的频率位置&#xff0c;这将有助于实现所需的系统性能。在该…

团队编程:提升代码质量与知识共享的利器

目录 前言1. 什么是团队编程&#xff1f;1.1 团队编程的起源1.2 团队编程的工作流程 2. 团队编程的优势2.1 提高代码质量2.2 促进知识共享2.3 增强团队协作2.4 提高开发效率 3. 团队编程的挑战3.1 开发成本较高3.2 需要良好的团队协作3.3 个人风格和习惯的差异3.4 长时间的集中…

大数据期末复习——hadoop、hive等基础知识

一、题型分析 1、Hadoop环境搭建 2、hadoop的三大组件 HDFS&#xff1a;NameNode&#xff0c;DataNode&#xff0c;SecondaryNameNode YARN&#xff1a;ResourceManager&#xff0c;NodeManager &#xff08;Yarn的工作原理&#xff09; MapReduce&#xff1a;Map&#xff0…

七人互助拼团模式:共创共赢的电商新篇章

在当今电商行业的繁荣浪潮中&#xff0c;七人互助拼团模式犹如一股清流&#xff0c;凭借其独特的激励机制与深厚的互助合作文化&#xff0c;赢得了消费者与商家的广泛赞誉。这一模式不仅重新定义了团购体验&#xff0c;更在无形中强化了社群间的联系与协作&#xff0c;共同绘制…

中英双语介绍日本东京(Tokyo)

中文版 东京介绍 东京是日本的首都&#xff0c;也是日本的政治、经济、文化和国际交流中心。以下是对东京的详细介绍&#xff0c;包括其地理位置、人口、经济、教育、文化和主要景点。 地理位置 东京位于日本关东地区的南部&#xff0c;地理坐标大致为北纬35度41分&#xf…

C语言_练习题

求最小公倍数 思路&#xff1a;假设两个数&#xff0c;5和7&#xff0c;那么最小至少也要7吧&#xff0c;所以先假定最小公倍数是两个数之间较大的&#xff0c;然后看7能不能同时整除5和7&#xff0c;不能就加1继续除 int GetLCM(int _num1, int _num2) {int max _num1>_n…

C++11中新特性介绍-之(二)

11.自动类型推导 (1) auto类型自动推导 auto自动推导变量的类型 auto并不代表某个实际的类型&#xff0c;只是一个类型声明的占位符 auto并不是万能的在任意场景下都能推导&#xff0c;使用auto声明的变量必须进行初始化&#xff0c;以让编译器推导出它的实际类型&#xff0c;…

Python入门 2024/7/6

目录 数据容器入门 列表的定义语法 基本语法 嵌套列表 ​编辑 列表的下表索引 ​编辑 列表的常用操作 列表的常见方法 查找元素的下标 修改下标索引的值 插入元素 追加元素 追加一批元素 删除元素 删除某元素在列表中的第一个匹配项 清空列表内容 统计元素在…

2024亚太杯中文赛数学建模B题完整论文讲解(含每一问python代码+结果+可视化图)

大家好呀&#xff0c;从发布赛题一直到现在&#xff0c;总算完成了2024 年第十四届 APMCM 亚太地区大学生数学建模竞赛B题洪水灾害的数据分析与预测完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人…

web服务之Nginx

web服务之Nginx &#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Li…