C#中委托与事件

news2024/11/17 10:31:24

一、委托

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.coloradmin.cn/o/1900682.html

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

相关文章

雨量监测站:守护大地的晴雨表

雨量监测站是一种专门用于测量和记录降雨量的设施。它通常由雨量计、数据采集器、传输装置和数据处理系统组成。雨量计负责感应雨滴的接触&#xff0c;通过一定的机制将降雨量转化为电信号或数字信号。数据采集器则负责收集这些信号&#xff0c;并将其传输至数据处理系统进行分…

【nvm管理nodejs版本,切换node指定版本】

nvm管理nodejs版本 nvm管理nodejs版本主要功能使用 nvm nvm管理nodejs版本 nvm&#xff08;Node Version Manager&#xff09;顾名思义node版本管理器&#xff0c;无须去node管网下载很多node安装程序;用于管理多个 Node.js 版本的工具。它允许你在同一台机器上同时安装和管理…

WPF自定义模板--RadioButton

默认格式 <Style x:Key"RadioButtonStyle" TargetType"{x:Type RadioButton}"><Setter Property"FocusVisualStyle" Value"{StaticResource FocusVisual}"/><Setter Property"Background" Value"{Stat…

Autosar MCAL-S32k324 Crypto配置-RandomNumber生成及使用

文章目录 前言CryptoPrimitivesCryptoPrimitiveAlgorithmFamilyCryptoPrimitiveAlgorithmModeCryptoPrimitiveAlgorithmSecondaryFamilyCryptoPrimitiveServiceCryptoDriverObject代码使用Random Generate执行流程配置job函数使用示例总结前言 之前介绍过AES-CMAC算法的配置,…

计算机专业怎么选择电脑

现在高考录取结果基本已经全部出来了&#xff0c;很多同学都如愿以偿的进入到了计算机类专业&#xff0c;现在大部分同学都在为自己的大学生活做准备了&#xff0c;其中第一件事就是买电脑&#xff0c;那计算机类专业该怎么选择电脑呢&#xff1f; 计算机专业是个一类学科&…

VBA初学:零件成本统计之四(汇总计算)

第四步&#xff0c;最后进行汇总计算 汇总统计的计算 Sub count() Dim rng As Range Dim i As Long, j As Long Dim arr_s, arr, brr, crr, drr Dim rowscount As Long Dim X As Variant Dim rg As Single, xb As Single, zj As SingleMsgBox "汇总计算时间较久&#xff…

实战某大型连锁企业域渗透

点击星标&#xff0c;即时接收最新推文 本文选自《内网安全攻防&#xff1a;红队之路》 扫描二维码五折购书 实战域渗透测试流程 对黑客来说&#xff0c;拿下域控制器是终极目标。然而攻击者空间是如何通过采取信息收集、权限提升、横向移动等一系列手段&#xff0c;从而一步步…

白嫖A100活动-入门篇-1.Linux+InterStudio

进入InterStudio 这节课是为了让大家熟悉使用InterStudio平台&#xff0c;以便后续开发 InterStudio平台是算力平台&#xff0c;可以通过平台使用A100,还可以使用“书生”团队集成好的环境、工具&#xff0c;快速部署LLMs. 进入平台&#xff1a; 记得报名&#xff0c;获得免…

vue2响应式原理+模拟实现v-model

效果 简述原理 配置对象传入vue实例 模板解析&#xff0c;遍历出所有文本节点&#xff0c;利用正则替换插值表达式为真实数据 data数据代理给vue实例&#xff0c;以后通过this.xxx访问 给每个dom节点增加观察者实例&#xff0c;由观察者群组管理&#xff0c;内部每一个键值…

集成学习(一)Bagging

前边学习了&#xff1a;十大集成学习模型&#xff08;简单版&#xff09;-CSDN博客 Bagging又称为“装袋法”&#xff0c;它是所有集成学习方法当中最为著名、最为简单、也最为有效的操作之一。 在Bagging集成当中&#xff0c;我们并行建立多个弱评估器&#xff08;通常是决策…

52-3 权限维持 - IFEO注入(镜像劫持)

IFEO注入(映像劫持)介绍 IFEO(Image File Execution Options)位于Windows注册表中的路径为: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options IFEO最初设计用于为在默认系统环境下可能出现错误的程序提供特殊的调试和执…

JavaWeb开发之环境准备-大合集

本文博客地址 JavaWeb开发 || 环境准备 1. 前言2. JDK8安装2.1 下载地址2.2 安装配置图示2.2.1 JDK安装2.2.2 配置系统环境变量 3. Maven安装3.1 Maven下载3.2 Maven解压及系统变量配置 4. Tomcat安装4.1 Tomcat下载4.2 Tomcat解压及系统变量配置 5. Redis安装5.1 Redis下载5.…

【postgresql】 基础知识学习

PostgreSQL是一个高度可扩展的开源对象关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;它以其强大的功能、灵活性和可靠性而闻名。 官网地址&#xff1a;https://www.postgresql.org/ 中文社区&#xff1a;文档目录/Document Index: 世界上功能最强大的开源…

顶顶通呼叫中心中间件-外呼通道变量同步到坐席通道变量(mod_cti基于Freeswitch)

机器人伴随转人工或者排队转人工 把外呼通道同步到坐席通道变量 在拨号方案转人工动作cti_acd,或者转机器人动作cti_rotobt的前面&#xff0c;添加一个 export nolocal:变量名${变量名} 一、配置拨号方案 win-ccadmin配置方法 点击拨号方案 -> 点击进入排队 -> 根据图…

liunx文件系统,日志分析

文章目录 1.inode与block1.1 inode与block概述1.2 inode的内容1.3 文件存储1.4 inode的大小1.5 inode的特殊作用 2.硬链接与软链接2.1链接文件分类 3.恢复误删除的文件3.1 案例:恢复EXT类型的文件3.2 案例:恢复XFS类型的文件3.2.1 xfsdump使用限制 4.分析日志文件4.1日志文件4.…

Ant Design Pro修改菜单栏的颜色

一&#xff1a;修改菜单栏的配色 第一步&#xff1a; 修改defaultSetting--> ProLayoutProps 中的属性值 sider: {colorMenuBackground: #fff, // menu 的背景颜色colorBgMenuItemHover: #91d5ff, // menuItem 的 hover 背景颜色colorTextMenu: #607AAF, // menuItem 的字…

智能与伦理:Kimi与学术道德的和谐共舞

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 Kimi&#xff0c;由月之暗面科技有限公司开发的智能助手&#xff0c;擅长中英文对话&#xff0c;能处理多种文档和网页内容。在论文写作中&#xff0c;Kimi可提供资料查询、信息整理、语…

2024年【金属非金属矿山(地下矿山)安全管理人员】考试报名及金属非金属矿山(地下矿山)安全管理人员模拟考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年金属非金属矿山&#xff08;地下矿山&#xff09;安全管理人员考试报名为正在备考金属非金属矿山&#xff08;地下矿山&#xff09;安全管理人员操作证的学员准备的理论考试专题&#xff0c;每个月更新的金属非…

KVM虚机调整磁盘大小(注:需重启虚拟机)

1、将磁盘大小由15G调整为25G [rootkvm ~]# virsh domblklist kvm-client #显示虚拟机硬盘列表 [rootkvm ~]# qemu-img resize /var/lib/libvirt/images/tesk-disk.qcow2 10G #扩容 [rootkvm ~]# qemu-img info /var/lib/libvirt/images/test-disk.qcow2 #查看信息 注&…

【论文通读】A Survey of Neural Code Intelligence: Paradigms, Advances and Beyond

A Survey of Neural Code Intelligence: Paradigms, Advances and Beyond 前言摘要代码模型的发展神经语言建模代码预训练模型大型语言模型 学习范式的转移数据集与评测基准跨领域协同应用与未来资源阅读总结 前言 神经代码智能利用深度学习理解、生成和优化代码&#xff0c;连…