委托和事件

事件的由来

上文说到委托的安全性不佳,于是我们要将委托本身私有化,但还要暴露若干方法让外界使用。其中最重要的必然就是为委托挂接方法和调用委托,以便间接地调用委托所代表方法。那么事件event关键字就是c#提供给我们的一个语法糖。他并没有任何新的东西,只是减少了一些代码。所以,事件是一种特殊的委托,其特征有:

1 和一个(基底)委托类型合作,当声明了一个具有该基底委托类型的事件之后,用户在外部就可以为这个事件挂接方法,其方法类型必须和基底委托类型相同

2 可以将事件视为委托的方法链,使用event关键字时,该方法链是私有的,而使用委托类型名作为关键字时,该方法链是公共的

3 事件虽然是私有的,但编译器自动为我们建立了两个隐藏方法,并重载了+=和-=,使得我们可以不编写任何额外的代码,利用+=和-=操作事件上的方法,从而控制当事件触发时执行什么方法

复制代码
public class Program{public static void Main() { //创建了一个新的订阅者 var c = new Car("Mycar", 0, 100); //还记得委托么,如果methodList是一个CarEngineHandler类型则可以这样写 //现在methodList是一个事件类型,这样写会报错 //事件只能出现在+=或者-=的左方,不能出现在等于号的左方 //故此时用户不能随意为其赋值,保证了安全 c.methodList = OnCarEvent1; //这是正确的 c.methodList += OnCarEvent1; //不能在外部这样调用一个事件 //c.methodList.Invoke() } public static void OnCarEvent1(string msg) { Console.WriteLine("***** message from car *****"); Console.WriteLine("=> " + msg); Console.WriteLine("****************************"); } public static void OnCarEvent2(string msg) { Console.WriteLine("=> " + msg.ToUpper()); } } public class Car { public string name { get; set; } public int currentSpeed { get; set; } public int MaxSpeed { get; set; } private bool isDead { get; set; } public delegate void CarEngineHandler(string message); public event CarEngineHandler methodList; public Car(string name, int currentSpeed, int MaxSpeed) { this.name = name; this.currentSpeed = currentSpeed; this.MaxSpeed = MaxSpeed; this.isDead = false; } public void Accel(int delta) { //死亡时执行订阅列表中的方法 if (isDead) { if (methodList != null) //在内部调用事件和调用委托没区别 methodList("Sorry, car is broken"); } else { currentSpeed += delta; if (currentSpeed >= MaxSpeed) isDead = true; else Console.WriteLine("Current speed: " + currentSpeed); } } }
复制代码

 

事件的代码规范

微软为事件设置了代码规范,和委托相同,这些规范主要有:

1 委托名必须以Handler结尾

2 委托必须有且仅有两个参数,第一个为object类型的sender,第二个则是一个集成了EventArgs类型的自定义类类型,名字可以自定

那么我们使用代码规范来重新写一下上面的例子:

复制代码
public class Program{public static void Main() { //创建了一个新的订阅者 var c = new Car("Mycar", 0, 100); c.methodList += OnCarEvent1; for (int i = 0; i < 10; i++) { c.Accel(20); } Console.ReadKey(); } public static void OnCarEvent1(object sender, CarEventArgs e) { //现在我们知道是谁触发了事件 Console.WriteLine("***** message from car: " + sender.ToString() + " *****"); Console.WriteLine("=> " + e.message); Console.WriteLine("****************************"); } } public class Car { public string name { get; set; } public int currentSpeed { get; set; } public int MaxSpeed { get; set; } private bool isDead { get; set; } //标准化的委托定义 //sender: 当发生事件时,告知订阅者是谁触发了事件 //e: 当发生事件时传递的信息(可以自定义一个类继承EventArgs类,故可以传递任意类型的信息) public delegate void CarEngineHandler(object sender, CarEventArgs e); public event CarEngineHandler methodList; public Car(string name, int currentSpeed, int MaxSpeed) { this.name = name; this.currentSpeed = currentSpeed; this.MaxSpeed = MaxSpeed; this.isDead = false; } public void Accel(int delta) { //死亡时执行订阅列表中的方法 if (isDead) { if (methodList != null) //在内部调用事件和调用委托没区别 methodList(name, new CarEventArgs { message = "Sorry, this car is dead." } ); } else { currentSpeed += delta; if (currentSpeed >= MaxSpeed) isDead = true; else Console.WriteLine("Current speed: " + currentSpeed); } } } //自定义事件发生时发送的信息格式 public class CarEventArgs : EventArgs { public string message { get; set; } }
复制代码

 

sender和EventArgs

相信很多人在使用.net进行控件的拖拽时,如果拖拽一个按钮,然后双击它,就会发现代码多了几行(省略了无关的):

this.button1.Click += new System.EventHandler(this.button1_Click);
private void button1_Click(object sender, EventArgs e)
{
}

但可能不是所有人都明白那两个参数是做什么的,反正我在这个方法里写代码,然后点击那个按钮,编译器就会执行到这里面的代码。其实这正是符合微软命名规范的一个事件的例子。

1. 在初始化时,为这个对象的Click属性(注意该属性的类型是一个事件,他的基底委托是EventHandler类型的)绑定了button1_Click方法。此时如果这个事件被调用,那么就会执行button1_Click方法的代码。

EventHandler 是C#控件中最常见的委托,它没有返回类型:

public delegate void EventHandler (Object sender, EventArgs e)

我们注意到,这个委托正好和button1_Click方法签名相同,也就是说,我们可以将button1_Click方法加入到委托的方法链中。而在这里,方法链就是事件类型变量Click。

2. 当单击按钮时,经过一系列的消息轮询最终系统捕获到了你的单击动作,再经过一系列处理,最后到了Control.OnClick(System.EventArgs e)方法

3. 在这个方法里调用事件

复制代码
        protected virtual void OnClick(EventArgs e){//从Events委托集合中取出名为EventClick的委托 EventHandler handler = (EventHandler)base.Events[EventClick]; //如果不为空则执行这个委托上的方法,也就是button1_Click if (handler != null) { //this就是button1 handler(this, e); } }
复制代码

 

大略的整个过程就是:

1. 你的点击动作被windows捕获,windows把这个动作(this.button1.Click)作为系统消息发送给程序(底层消息轮询机制)

2. 程序从自己的消息队列中不断的取出消息,并在消息循环中寻找对应的处理方式

3. 对于这个消息,其sender(事件的来源)就是这个按钮,发送的消息全部在e里面,在某些事件里,e用处不大,比如在MouseEventArgs的Mouse事件中,可以看到e包括mouse的坐标值等,以供你的程序使用

4. 因为this.button1.Click挂接了方法button1_Click,故执行这里面的代码

所以说实际上当单击按钮时,其实编译器已经帮我们做了很多事情,例如委托的建立,事件的挂接和执行,这些都已经被封装到你根本就不需要知道也可以编写出来成功执行的代码的程度了。那么委托和事件这个话题差不多就结束了(在c#1.0这个层面上)。在更高版本的c#中,委托和事件被包装的更加简便易用了,基于泛型的委托action和func的出现,更是(基本上)完全替代了原生的委托delegate。这些精彩的内容当然要等待到介绍c#2和3的时候一块讲述。

转载于:https://www.cnblogs.com/lishuyi/p/4270213.html

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

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

相关文章

HiveQL: 数据操作

文章目录1. 向管理表中装载数据2. 通过查询语句向表中插入数据3. 动态分区插入4. 从单个查询语句创建表并加载数据5. 导出数据学习自《Hive编程指南》 1. 向管理表中装载数据 hive (default)> load data local inpath "/home/hadoop/workspace/student.txt">…

formdata.append加多个值_redis的五种数据结构和应用场景:微博微信点赞+加购物车等...

Redis五种数据结构如下&#xff1a;1.String 字符串类型是redis中最基本的数据类型&#xff0c;一个key对应一个value。String类型是二进制安全的&#xff0c;意思是 redis 的 string 可以包含任何数据。如数字&#xff0c;字符串&#xff0c;jpg图片或者序列化的对象。2.Hash …

iOS开发-自动隐藏键盘及状态栏

1.隐藏状态栏 iOS升级至7.0以后&#xff0c;很多API被废止&#xff0c;其中原有隐藏状态栏StatusBar的方法就失效了。 原有方案 [[UIApplication sharedApplication] setStatusBarHidden:YES]; 但很不幸&#xff0c;在后来的版本中实效了&#xff0c;因此我们可以使用新的API来…

python gevent模块 下载_【python安全攻防】包、模块、类、对象

终于又到了一周一度的整理博客的时间了&#xff0c;博主平时课余时间看书&#xff0c;周末统一整理&#xff0c;坚持周更真是爱了爱了 &#xff5e;今天要说的是python面向对象这一部分的内容&#xff0c;今天这是基础篇的第二篇&#xff0c;也是最后一篇。说来基础篇还真是少呢…

LeetCode LCP 33. 蓄水(暴力枚举)

文章目录1. 题目2. 解题1. 题目 给定 N 个无限容量且初始均空的水缸&#xff0c;每个水缸配有一个水桶用来打水&#xff0c;第 i 个水缸配备的水桶容量记作 bucket[i]。小扣有以下两种操作&#xff1a; 升级水桶&#xff1a;选择任意一个水桶&#xff0c;使其容量增加为 buck…

302状态码_你见过 HTTP 哪些状态码?

❝好久没有写技术文章&#xff0c;今天在四川广元无事&#xff0c;总结一篇。附一张今天早上在嘉陵江遇见的白鹡鸰 (不是我拍的)❞白鹡鸰101 Switch Protocol200 Ok201 Created204 No Content206 Partial Content301 Moved Permanently302 Found304 Not Modified307 Temporary …

LeetCode LCP 34. 二叉树染色(树上DP)

文章目录1. 题目2. 解题1. 题目 小扣有一个根结点为 root 的二叉树模型&#xff0c;初始所有结点均为白色&#xff0c;可以用蓝色染料给模型结点染色&#xff0c;模型的每个结点有一个 val 价值。 小扣出于美观考虑&#xff0c;希望最后二叉树上每个蓝色相连部分的结点个数不能…

delphi 串口通信发送_关于串口通信232、485、422和常见问题,就没见过能讲这么清楚的...

先讲串口通信的一些基本概念&#xff0c;术语。如果对串口通信比较熟悉的&#xff0c;就当复习&#xff0c;如果哪里讲的不到位&#xff0c;欢迎及时指出。这里并不对串口的编程作讲解&#xff0c;主要是从应用的角度去讲一讲。因为更多的时候&#xff0c;都是产品做好了&#…

LeetCode 1822. 数组元素积的符号

文章目录1. 题目2. 解题1. 题目 已知函数 signFunc(x) 将会根据 x 的正负返回特定值&#xff1a; 如果 x 是正数&#xff0c;返回 1 。如果 x 是负数&#xff0c;返回 -1 。如果 x 是等于 0 &#xff0c;返回 0 。 给你一个整数数组 nums 。 令 product 为数组 nums 中所有元…

快速替换图片的组合-AE-样片!

模板下载网址&#xff1a;http://pan.baidu.com/s/1hqCbErM转载于:https://www.cnblogs.com/nedtwo/p/4278337.html

南昌理工学院计算机网络技术专业怎么样,南昌理工学院怎么样 重点专业是什么...

毕业季即将来临&#xff0c;报考的时候同学们和家长朋友们最关心的就是学校好不好的问题&#xff0c;想要了解学校有哪些特色专业、师资力量怎么样。下面小编整理了南昌理工学院的信息&#xff0c;供大家参考。南昌理工学院重点专业国家级特色专业&#xff1a;计算机科学与技术…

matplotlib绘图_使用matplotlib库绘图

本代码演示对列表元素进行绘图并可视化代码如下&#xff1a;import matplotlib.pyplot as plt #导入matplotlib绘图库&#xff0c;并设置简称为pltlist1[i*2 for i in range(1,10)] #遍历range(1,10)里的元素&#xff0c;并每个乘以2&#xff0c;并将最终的列表赋值给list1plt.…

LeetCode 1824. 最少侧跳次数(DP)

文章目录1. 题目2. 解题1. 题目 给你一个长度为 n 的 3 跑道道路 &#xff0c;它总共包含 n 1 个 点 &#xff0c;编号为 0 到 n 。 一只青蛙从 0 号点第二条跑道 出发 &#xff0c;它想要跳到点 n 处。然而道路上可能有一些障碍。 给你一个长度为 n 1 的数组 obstacles &a…

postman 使用_Postman简单使用

今天主要讲解下Postman的简单使用。在使用前&#xff0c;首先需要了解一下什么是Postman&#xff0c;它可以用来做什么&#xff1f;1、 Postman是一款自动化测试的工具&#xff0c;它可以方便的处理HTTP的请求(get、post、put、delete等)。本文主要讲解get和post的使用。2、 那…

中山大学校队选拔赛第二试题试题3【Compressed suffix array】-------2015年2月8日

一&#xff1a;题目大意 本题通过给定三个数组S0&#xff0c;P&#xff0c;S&#xff0c;其中S0是1到2n的一个排列&#xff0c;P具有2n个整数&#xff0c;且满足&#xff1a; 数组S是把数组S0中所有奇数元素全部删除并将所有偶数元素除以2并按照原来的相对顺序进行排列而得。 现…

LeetCode 1825. 求出 MK 平均值(set + queue)

文章目录1. 题目2. 解题1. 题目 给你两个整数 m 和 k &#xff0c;以及数据流形式的若干整数。 你需要实现一个数据结构&#xff0c;计算这个数据流的 MK 平均值 。 MK 平均值 按照如下步骤计算&#xff1a; 如果数据流中的整数少于 m 个&#xff0c;MK 平均值 为 -1 &#…

maven deploy plugin_Maven快速上手

作者&#xff1a;u_7deeb657158f出自&#xff1a;ITPUB博客原文&#xff1a;blog.itpub.net/69956102/viewspace-2726121/创建项目首先需要创建一个用于存储项目的文件夹&#xff0c;在控制台中输入以下命令&#xff1a;mvn archetype:generate -DgroupIdcom.mycompany.app -Da…

.net string format

转自&#xff1a;http://www.cnblogs.com/jobs2/p/3948049.html 转自&#xff1a;http://jingyan.baidu.com/article/48206aeaf8c52f216ad6b300.html 1、格式化货币&#xff08;跟系统的环境有关&#xff0c;中文系统默认格式化人民币&#xff0c;英文系统格式化美元&#xff0…

python画饼图_百度飞桨PaddlePaddle之[Python小白逆袭大神]7天训练营

第三次参加百度的7天训练营了这次参加的主题是【Python小白逆袭大神】&#xff0c;不过你别看是小白逆势。。。除非你一开始参加就逆袭完&#xff0c;不然你真的是python小白&#xff0c;这个课程还是有难难度的。说一下个训练营的特点版。这个营从python一些基础练习-->数据…

潍坊学院的计算机类怎么样,潍坊学院教育技术学专业怎么样?有知道的麻烦说下,谢谢!...

潍坊学院教育技术学专业怎么样&#xff1f;有知道的麻烦说下&#xff0c;谢谢&#xff01;以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;潍坊学院教育技术学专业怎么样&#xff1f;有知道的…