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个人按职责划分为上单、打野、辅助、中单、辅助。这里主要是通过打野和上单的一个简单互动来说明一下事件的触发机制。具体的代码如下:

 1 using System;
 2 using System.Threading;
 3
 4 namespace EventStudy
 5 {
 6
 7
 8
 9     public class Top  //事件发布者(上单)
10     {
11         public string Hero { get; set; } //使用的英雄
12         public int hp { get; set; } = 500; //英雄生命值
13         public delegate void LowHphandler(object sender, LowHpEventArgs e); //声明一个微软标准类型的委托
14         public event LowHphandler LowHpEvent; //声明一个该委托类型的事件
15
16         public class LowHpEventArgs : EventArgs //低生命事件信息
17         {
18             public readonly string LowHpHero;
19             public int restHp { get; set; }
20             public LowHpEventArgs(string hero, int _resthp)
21             {
22                 LowHpHero = hero;
23                 restHp = _resthp;
24             }
25         }
26
27         public void BackToBase() //回城补给
28         {
29             Console.WriteLine("{0}回城了",Hero);
30             hp = 500;
31             Thread.Sleep(3000);
32             Console.WriteLine("他传送回了上路");
33         }
34
35         public Top(string hero) //构造函数
36         {
37             Hero = hero;
38         }
39
40
41         public void fight(int battleCounts )//战斗  battleCounts = 战斗次数
42         {
43             for(int i = 0; i < battleCounts;i++) //战斗流程
44             {
45                 Console.WriteLine("我方上单{0}正在与对方上单激烈对线中......",Hero);
46                 Thread.Sleep(2000);
47                 hp -= 100;
48                 Console.WriteLine("交战后剩余生命值:{0}", hp);
49                 Thread.Sleep(1000);
50                 if(hp <= 100)  //当生命值小于等于100时
51                 {
52                         if (LowHpEvent != null) //如果有对象注册
53                             LowHpEvent(this, new LowHpEventArgs(Hero, hp)); //触发事件
54                         else
55                             Console.WriteLine("{0}说:草,没人关注上路啊?",Hero);
56                     break;
57                 }
58             }
59         }
60
61     }
62
63     class Jungle //订阅者(打野)
64     {
65             public string HeroName; //使用的英雄名字
66             public Jungle(string name)//构造函数
67             {
68                 HeroName = name;
69             }
70             public void Help(object sender,Top.LowHpEventArgs e)//回调函数,或者说事件处理程序
71             {
72                 Console.WriteLine("{0}说:卧槽,我们的上单{1}只有:{2}血了,我得去帮他",HeroName, e.LowHpHero, e.restHp);
73             }
74     }
75
76
77
78     class Program
79     {
80         static void Main(string[] args)
81         {
82             //创建一个上单和一个打野
83             Top Yassuo = new Top("疾风剑豪-亚索");
84             Jungle Leesin = new Jungle("盲僧-李青");
85
86             Yassuo.LowHpEvent += Leesin.Help; //李青开始关注着亚索的生命情况
87             Yassuo.fight(4); //亚索开始和对面对线 当达到特定情况时触发事件,然后执行对应的委托(即回调已经注册了的李青的Help方法)
88             Yassuo.BackToBase(); //亚索血量过低回城了 重置hp为500
89             Yassuo.LowHpEvent -= Leesin.Help; //亚索回城了,李青不再关注
90             Yassuo.fight(4); //亚索继续和对面对线 当达到特定情况时又触发事件,但李青已经取消关注,事件处理为空,所以直接打印亚索要说的话
91             Console.ReadLine(); //Pause
92         }
93     }
94 }

对应的控制台输出如下:

这里概括来说主要就是盲僧的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 。

时间: 2024-10-12 21:52:49

C#学习(一):委托和事件的相关文章

C#学习:委托、事件、匿名方法

一.委托: 委托给我的感觉就是一个种类型,可以让方法更具面向对象的特性——你看,其实我也没说明白,因为我也不大理解.还是一步步往下学吧. 具体来说,委托就是一个类似下面的这种东西: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; namespace ConsoleTestCsharp { class Program { d

.net学习之委托和事件

1.什么是委托通俗的说:委托就是一个能够存储符合某种格式(方法签名)的方法的指针的容器上传图片: 2.委托语法准备一个方法:string Hello(string userName){} string Hello2(string userName){}声明委托类:delegate string DGSayHi(string userName);创建委托对象:DGSayHi dgSay = new DGSayHi(Hello); 或 DGSsyHi dgSay = Hello;追加方法:dgSay

(转).net学习之委托和事件

.net学习之委托和事件 1.什么是委托 通俗的说:委托就是一个能够存储符合某种格式(方法签名)的方法的指针的容器 上传图片: 2.委托语法 准备一个方法:string Hello(string userName){}        string Hello2(string userName){} 声明委托类:delegate string DGSayHi(string userName); 创建委托对象:DGSayHi dgSay = new DGSayHi(Hello); 或 DGSsyHi

委托 ,事件,泛型学习总结

委托 ,事件,泛型学习总结 C# 委托 一图流: 委托.png 如果这些内容帮助到你了,希望您给予支持 o(^ ▽ ^)o

C#委托与事件学习笔记

今天跟随视频学习了一下C#中最重要的一些概念之委托与事件.老杨的视频讲的还是挺深入浅出,不过刚接触C#.NET的人还是朦朦胧胧,就像张子阳先生说的"每次见到委托和事件就觉得心里别(biè)得慌,混身不自在".跨过这道坎的人就有种一览众山小的感觉了.我又浏览了皱华栋老师JamesZou的博文<深入理解C#委托及原理>(地址:http://www.cnblogs.com/jameszou/archive/2011/07/21/2112497.html),以及张子阳Jimmy Z

C#学习之初步理解委托、事件、匿名方法和Lambda

最经在学习LinqtoSql,然后扯到Lambda表达式,然后扯到匿名方法,然后扯到委托,最后扯到事件处理...后来发现对委托这个概念和事件处理这个过程理解得不是很清晰,遂得一下学习笔记.那里说得不对,请大家多多指教! 第一部分:理解委托 委托委托,顾名思义,就是类似于中间人的意思,有些事情你不做,委托别人去做,比如你想相亲,但你不想去主动约女孩子,那你可以交给媒婆去帮你约. 如果你学过C++,请把委托理解成函数指针,都是为了调用函数.函数指针可以调用符合该函数指针要求的函数.什么叫符合该函数指

C#委托,事件最初浅的和最易看懂的学习笔记

对于委托和事件,看了不少博文,当时好像都理解了,过了一段时间,又忘记的差不多了.每每如此,感觉自己很笨,记性差,其实是没有深入理解透切,没有按照自己的语言表达出来,当然容易忘记.今天又花了一些时间,好好理解,总结别人的文章,用自己文字概况出来. 总结如下: 委托可以定义任何地方,应该说是委托声明 事件类可以单独放一个地方,包含一些属性 事件一定定义在发布者里面,应该说是事件声明,并在这里做判断注册事件,给事件类属性赋值 订阅者,也就是事件的受理者,它里面有些方法并后续操作. 客户端把发布者与订阅

c#学习系列之委托与事件

1. 引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见到委托和事件就觉得心里别(biè)得慌,混身不自在.本文中,我将通过两个范例由浅入深地讲述什么是委托.为什么要使用委托.事件的由来..Net Framework中的委托和事件.委托和事件对Observer设计模式的意义,对它们的中间代码也做了讨论. 2. 将方法作为方法的参数 我们先

C#高级知识点概要(1) - 委托和事件

作者:linybo 要成为大牛,必然要有扎实的基本功,不然时间再长项目再多也很难有大的提升.本系列讲的C# 高级知识点,是非常值得去撑握的,不仅可以让你写代码时游刃有余,而且去研究和学习一些开源项目时,也不会显得那么吃力了. 希望大家记住,这里讲的所有的知识点,不仅仅是了解了就可以了,还要会灵活用,一定要多思考,撑握其中的编程思想. 本文讲的是委托和事件,这两个词可能你早就耳熟能详,但你是否真正撑握了呢? 本系列讲的C#高级知识点都是要求开发时能达到可以徒手写出来的水平(不依赖搜索引擎.找笔记等