C#学习(一):委托和事件
预备知识
在学习委托和事件之前,我们需要知道的是,很多程序都有一个共同的需求,即当一个特定的程序事件发生时,程序的其他部分可以得到该事件已经发生的通知。
而发布者/订阅者模式可以满足这种需求。简单来说,在这种模式中,发布者定义了一系列程序的其他部分可能感兴趣的事件。其他类可以“注册”,以便再这些事件发生时发布者可以通知它们。这些订阅者类通过向发布者提供一个方法来“注册”以获取通知。当事件发生时,发布者“触发事件”,然后执行订阅者提交的所有事件。
注:由订阅者提供的方法称为回调方法,或者说回调函数,关于回调函数可以参考https://www.zhihu.com/question/1980113 。
大概了解了下基本机制后,我们再来看看委托和事件:
什么是委托?
委托和类一样,是一种用户自定义的类型。但类表示的是数据和方法的集合,而委托则持有一个或多个方法,以及一系列预定义操作(你可以暂时把它理解成一个类型安全的C++函数指针)。可以通过以下操作来使用委托:
1)声明一个委托类型(类似方法声明,但委托没有实现块)
public delegate void MyDel(int x);
//格式为[修饰符] [委托关键字delegate] [返回类型][委托名][签名]
2)使用该委托类型声明一个委托变量。
MyDel delVar;
3)创建委托类型的对象,把它赋值给委托对象。新的委托对象包括指向某个方法的引用,这个方法和第一步的签名和返回类型一致。
创建委托对象可以这样:
delVar = new MyDel(SomeClass.Method);
//创建委托并保存第一个个方法的引用
或者使用快捷语法,比如这样:
delVar = SomeClass.Method;
4 )也可以为委托进行赋值,但这样旧的委托引用会被GC回收掉。
delVar = new MyDel(SomeClass.Method1);//创建一个新委托对象
delVar = OtherClass.Method2; //赋值后,之前的Method1的引用被Method2覆盖掉了
5)为委托对象增加或移除其他的方法
//增加方法
delVar += someMethod1;
delVar += someMethod2; //移除方法
delVar -= someMethod1;
6)组合委托。可以将两个委托组合生成成一个新的委托,这个新的委托的调用列表连接了其他两个委托的调用列表副本。
MyDel delA = someClass.Method1;
MyDel delB = otherClass.Method2; MyDel delC = delA + delB;
7)调用委托。调用委托跟调用函数方法一样,参数必须同其调用列表中的方法一致。调用委托时会执行它的调用列表中的所有方法。(注:调用时委托不能为空)
delVar(Parameters);
其他注意事项:1.调用带返回值的委托时,委托的返回值为其调用列表中最后一个方法的返回值。2.调用带引用参数的委托时,参数会根据调用列表中的一个或多个方法的返回值二改变。
什么是事件?
一句话概括,事件就好像是专门用于某种特殊用途的简单委托的封装。或者说,事件包含了一个私有的委托(也就是说你无法直接访问事件的委托)。
另外,事件中可用的操作比委托要少,对于事件我们只可以添加、删除或调用事件处理程序。事件被触发时,它调用对应的委托来依次调用调用列表中的方法。
对于事件的使用,.Net框架提供了一种标准模式,它定义了一种标准的委托类型EventHandler。
EventHandler声明如下:
public delegate void EventHandler(object sender,EventArgs e)
// sender保存的是触发事件的引用,因为是object,所以可以匹配任何类型的实例 (可以使用as运算符拆箱转换)
// EventArgs是所有事件信息的基类,你可以自己声明一个继承自EventArgs的事件信息类来保存一些需要传递的数据信息。
声明EventHandler对应的事件:
public event EventHandler someEvent;
注:你可以按照 delegate void XXXXHandler(object sender,EventArgs e)的格式声明自定义的标准委托类型。
增加移除事件处理程序和委托类似,这里就不再赘述。
说了这么多,最好亲自动手实践一下,这样才能巩固自己学习的知识。
一个小小的应用例子
LOL是现在许多人(包括我)十分喜爱的一款很流行的5v5多人游戏,这个游戏里面的一方中5个人按职责划分为上单、打野、中单、ADC、辅助。这里主要是通过打野和上单的一个简单互动来说明一下事件的触发机制。具体的代码如下:
using System;
using System.Threading; namespace EventStudy
{ public class Top //事件发布者(上单)
{
public string Hero { get; set; } //使用的英雄
public int hp { get; set; } = ; //英雄生命值
public delegate void LowHphandler(object sender, LowHpEventArgs e); //声明一个微软标准类型的委托
public event LowHphandler LowHpEvent; //声明一个该委托类型的事件 public class LowHpEventArgs : EventArgs //低生命事件信息
{
public readonly string LowHpHero;
public int restHp { get; set; }
public LowHpEventArgs(string hero, int _resthp)
{
LowHpHero = hero;
restHp = _resthp;
}
} public void BackToBase() //回城补给
{
Console.WriteLine("{0}回城了",Hero);
hp = ;
Thread.Sleep();
Console.WriteLine("他传送回了上路");
} public Top(string hero) //构造函数
{
Hero = hero;
} public void fight(int battleCounts )//战斗 battleCounts = 战斗次数
{
for(int i = ; i < battleCounts;i++) //战斗流程
{
Console.WriteLine("我方上单{0}正在与对方上单激烈对线中......",Hero);
Thread.Sleep();
hp -= ;
Console.WriteLine("交战后剩余生命值:{0}", hp);
Thread.Sleep();
if(hp <= ) //当生命值小于等于100时
{
if (LowHpEvent != null) //如果有对象注册
LowHpEvent(this, new LowHpEventArgs(Hero, hp)); //触发事件
else
Console.WriteLine("{0}说:草,没人关注上路啊?",Hero);
break;
}
}
} } class Jungle //订阅者(打野)
{
public string HeroName; //使用的英雄名字
public Jungle(string name)//构造函数
{
HeroName = name;
}
public void Help(object sender,Top.LowHpEventArgs e)//回调函数,或者说事件处理程序
{
Console.WriteLine("{0}说:卧槽,我们的上单{1}只有:{2}血了,我得去帮他",HeroName, e.LowHpHero, e.restHp);
}
} class Program
{
static void Main(string[] args)
{
//创建一个上单和一个打野
Top Yassuo = new Top("疾风剑豪-亚索");
Jungle Leesin = new Jungle("盲僧-李青"); Yassuo.LowHpEvent += Leesin.Help; //李青开始关注着亚索的生命情况
Yassuo.fight(); //亚索开始和对面对线 当达到特定情况时触发事件,然后执行对应的委托(即回调已经注册了的李青的Help方法)
Yassuo.BackToBase(); //亚索血量过低回城了 重置hp为500
Yassuo.LowHpEvent -= Leesin.Help; //亚索回城了,李青不再关注
Yassuo.fight(); //亚索继续和对面对线 当达到特定情况时又触发事件,但李青已经取消关注,事件处理为空,所以直接打印亚索要说的话
Console.ReadLine(); //Pause
}
}
}
对应的控制台输出如下:

这里概括来说主要就是盲僧的Help方法注册了亚索的低血量事件lowHpEvent,当亚索低血量时触发了事件,然后通过相应的的委托回调了盲僧的Help方法。亚索回城后,盲仔取消了对亚索低血量事件的关注。所以之后亚索再次低血量时,因为没有对应的事件处理程序(LowHpEvent == null),所以亚索开始吐槽没人来上路。
参考的相关资料:
C#图解教程(第四版) 作者:[美]Daniel M.Solis
大白话系列之C#委托与事件 :http://www.cnblogs.com/wudiwushen/archive/2010/04/20/1703368.html 作者:波哥2010
知乎回调函数相关: https://www.zhihu.com/question/1980113 。
C#学习(一):委托和事件的更多相关文章
- C#学习之委托和事件
C#学习中,关于委托和事件的一些见解: 一.C语言中的函数指针 想要理解什么是委托,就要先理解函数指针的概念.所谓函数指针,就是指向函数的指针(等于没说-.-).比如我定义了两个函数square和cu ...
- C#学习之委托与事件
委托 语法: public delegate void MyDelegate(); 使用: 1.定义委托----public delegate void MyDelegate(); 2.注册委 ...
- .net学习之委托和事件
1.什么是委托通俗的说:委托就是一个能够存储符合某种格式(方法签名)的方法的指针的容器上传图片: 2.委托语法准备一个方法:string Hello(string userName){} string ...
- .NET委托和事件
.net学习之委托和事件 1.什么是委托 通俗的说:委托就是一个能够存储符合某种格式(方法签名)的方法的指针的容器 上传图片: 2.委托语法 准备一个方法:string Hello(string ...
- C#学习之初步理解委托、事件、匿名方法和Lambda
最经在学习LinqtoSql,然后扯到Lambda表达式,然后扯到匿名方法,然后扯到委托,最后扯到事件处理...后来发现对委托这个概念和事件处理这个过程理解得不是很清晰,遂得一下学习笔记.那里说得不对 ...
- C#委托与事件学习笔记
委托事件学习笔记 本文是学习委托和事件的笔记,水平有限,如有错漏之处,还望大神不吝赐教. 什么是委托?从字面意思来解释,就是把一个动作交给别人去执行.在实际开发中最常用的就是使一个方法可以当做一个参数 ...
- C#委托,事件最初浅的和最易看懂的学习笔记
对于委托和事件,看了不少博文,当时好像都理解了,过了一段时间,又忘记的差不多了.每每如此,感觉自己很笨,记性差,其实是没有深入理解透切,没有按照自己的语言表达出来,当然容易忘记.今天又花了一些时间,好 ...
- C#高级编程 (第六版) 学习 第七章:委托和事件
第七章 委托和事件 回调(callback)函数是Windows编程的一个重要方面,实际上是方法调用的指针,也称为函数指针. .Net以委托的形式实现了函数指针的概念,.Net的委托是类型安全的. 委 ...
- c#学习笔记03——委托和事件
委托:一种引用类型,这种类型可以用来定义方法签名,从而使用委托实现将方法作为参数传递给其他方法.类似于C++中的函数之争,使用委托使程序员可以将方法引用封装在委托对象内. 定义和声明委托: deleg ...
随机推荐
- 64位ubuntu14.04配置adb后提示没有那个文件或目录
1.配置完adb环境变量后在终端输入adb: ameyume@ameyume-HP-450-Notebook-PC:~$ adb /home/ameyume/adt-bundle-linux-x86_ ...
- 【63】关系数据库常用的sql语句总结
创建表 语法 CREATE TABLE <表名>(<列名> <数据类型>[列级完整性约束条件] [,<列名> <数据类型>[列级完整性约束条 ...
- 新版MATERIAL DESIGN 官方动效指南(二)
继上一篇,本文继续第二部分,从动效的速度.动态持续时间.通用持续时间和缓动曲线4个部分,教你创建平滑一致的Material Design 动效.再系统的干货都比不上官方的动效指南,西瓜就在这,赶紧来捡 ...
- 在GitHub上创建代码仓库
目前在GitHub上管理托管带代码的人越来越多了,今天也尝试了一次,顺便记下来,备用. 首先是在GitHub上创建一个代码仓库,创建完之后,GitHub上会有提示,这时进入项目目录执行下面的命令,顺便 ...
- permutations II(全排列 2)
题目要求 Given a collection of numbers that might contain duplicates, return all possible unique permuta ...
- 如何成为一个优秀的DBA
今天在群上跟技术友们聊天.发现有几个大学生,他们很担心自己找不到工作.我问他们理由,他们说我们没有经验,公司不要怎么办?这些孩子们的担心,让我感觉到奇怪. 如果我是一个公司的老总,我会有这两种考虑:要 ...
- 设计模式基础:类及类关系的UML表示
设计模式基础:类及类关系的UML表示 2009-10-26 17:00 by 宗哥, 1891 阅读, 1 评论, 收藏, 编辑 UML中,类关系分为这几种,泛化(generalization), 实 ...
- (转)go rabbitmq实践
转载自:http://www.cnblogs.com/shi-meng/p/4800080.html 1:驱动 本来打算自己写一个驱动的,后来发现github上面已经有了,那我就直接拿现成的了, 驱动 ...
- jtds驱动更新对一个老问题的解决
07年年末的一篇blog: 以前网站做初期开发时,有一个问题:hibernate下text大字符串读取时出这个异常:JDBCExceptionReporter - The amount of data ...
- clear read-only status问题的解决
IDEA系工具可能会报出的错误. 解决方法见官方文档吧:Changing Read-Only Status of Files : https://www.jetbrains.com/help/ide ...