.NET 委托和事件
2016-02-14 14:46
218 查看
什么叫委托
委托就是只想一个函数的指针,使用委托可以让方法的引用封装在委托对象内,例如我是老板,需要以后我渴了的时候让小蜜给我打杯水,饿了就让他给我打水,门上安装个门铃,一按就让她给我打水和送吃的。这样我就可以将委托,将引用方法(打水)封装到委托对象(小蜜),以后我一按门铃,那么就是告诉我小我要喝水了,要吃东西了,小蜜就给我打水,至于门铃到底代表了什么,不管,我只是我说我又饿又渴,哈哈哈,我是不是太懒了。委托实现
代码实现
其实学习.net的大家应该都知道有这么一个东西,那么我们就先看一下,这个家伙怎么用。例如一个简短的例子:<span style="font-size:14px;">class Program { //定义一个委托类型的saySomething,参数是name,返回值是void public delegate void saySomething(string name); static void Main(string[] args) { //调用委托方法 saySomething ss = new saySomething(saySome.sayHelloToChinese); ss += new saySomething(saySome.sayHelloToEnglish); ss("孟海滨"); ss("平晓微"); ss.Invoke("孟海滨"); Console.ReadLine(); } } public class saySome { /// <summary> /// 一个静态方法,简单的打印一句话 /// </summary> /// <param name="name">一个姓名的参数</param> public static void sayHelloToChinese(string name) { Console.WriteLine(name + ":你好"); } /// <summary> /// 一个静态方法,简单的打印一句话 /// </summary> /// <param name="name">一个姓名的参数</param> public static void sayHelloToEnglish(string name) { Console.WriteLine(name + ":hello"); } }</span>看一下运行结果
分析代码
1.public delegate void saySomething(string name); 这里申明了一个Delegate的类型,名称为saySomething,返回值是void,参数是string2.为什么在最开始我说是一个函数的指针呢,大家看这行代码: ss += new saySomething(saySome.sayHelloToEnglish);他代表的就是指向saySome.sayHelloToEnglish这个函数。当然他和C++的函数指针还是有区别的,首先他可以搭载多个函数,而C++只能搭载一个,委托是安全的,面向对象的。
3.Delegate在搭载多个方法时,可以通过+=增加搭载的函数,也可以通过-=来去掉Delegate中的某个函数。
什么时候用
加入有这么一个需求,汽车开车,当开到一定的距离的时候,报警器报警,就是是一次开到太多了,现在是汽车是一个实体,而报警器也是一个实体,如果用委托,他们可以这样实现。大家先看代码:汽车实体
<span style="font-size:14px;">public class Car { //定义委托类型,返回值是void,参数是int public delegate void Notify(int value); //定义一个事件 public event Notify notifiers; //定义一个汽油的变量 private int petorl; //汽油变量的set,get方法,在设置汽油数值的时候,判断汽油量是否充足 public int Petorl { get { return petorl; } set { petorl = value; //如果汽油量少于10 if (petorl < 10) { //如果委托的对象不为空 if (notifiers != null) { //执行委托的放方法,委托的是什么?在这里不体现。 notifiers.Invoke(Petorl); } } } } //构造函数,参数为汽油量(单位 :/L) public Car(int pertorl) { Petorl = pertorl; } //汽车启动的方法 public void run(int speed) { //行走公里变量,单位(km/h) int distance = 0; //根据汽油量进行循环 while (Petorl > 0) { //加上500ms跑speed公里 Thread.Sleep(500); //汽油逐渐减少 Petorl--; //行走公里数增加 distance += speed; Console.WriteLine("汽车当前跑的公里数是" + distance.ToString()); } } }</span>报警器
<span style="font-size:14px;">public class Alerter { //构造函数,将“显示汽油量不足的信息”的引用添加到汽车的委托中 public Alerter(Car car) { //为car.notifiers 添加NotEnoughPetorl的引用 car.notifiers += new Car.Notify(NotEnoughPetorl); } //显示汽油量不足的信息 public void NotEnoughPetorl(int value) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("汽油量不足了" + value.ToString()); Console.ResetColor(); } }</span>
客户端
<span style="font-size:14px;"> class Program { static void Main(string[] args) { //新建一个汽车,初始化的汽油量是15L Car car = new Car(15); //实例化报警器,将新建的气喘告诉他,让他添加一个油量不足的引用 new Alerter(car); //奔跑吧汽车 car.run(120); } }</span>
看到上边的代码,有的朋友就会说了,我不用再汽车(Car)类里边用委托,直接实例化Alerter也可以呀,直接实例化,如果汽油量少于10,我就实例化一个报警器,然后去执行油量不足的提醒,也可以呀!
是的,确实可以,但是看看如果我用了委托,我再汽车中有关于警报器的说法吗,是不是解耦合了,假如改天我的汽车改成烧气 的了,怎么办,我需要新加一个方法(提示天然气不足的),这个本来没什么,有了新的需求,增加代码本来就是应该的,但是我如果实例化报警器的话,那么我就需要修改汽车的类了,如果是委托呢,我执行要在报警器的类中做一定的扩充就可以,以前的代码完全不用改。这样看的话,是不是感觉委托更加牛了呢。
Delegate和event
大家可能看到上边有那么两句代码//定义委托类型,返回值是void,参数是int public delegate void Notify(int value); //定义一个事件 public event Notify notifiers;这个事件是什么鬼,为什么我在第一个代码示例中就可以实现委托的功能,却要假一个事件,event与纯粹的delegate变量的最大区别就是增加了封装性。让delegate的触发权完全由对象控制,而delegate所委托的实际函数则由订阅者决定。event就是要执行一种“什么时候发生我说了算,发生的时候做什么事你说了算“的效果。而纯粹的delegate变量则在可访问的范围内同时给与指定委托函数与触发的权限。
invoke和BeginInvoke的区别
在第一个例子我用到了ss("孟海滨"),ss.invoke("孟海滨"),为什么要用invoke,他是个什么鬼invoke和BeginInvoke有详细的解释,大家可以看一下,这里我就不解释了。委托小结
当我们在方法中需要函数指针等类似的东西的时候,当我们需要使用观察者模式的时候,当我们需要回掉函数的时候,可以考虑一下我们的委托,让我们降低类之间的耦合相关文章推荐
- 初识三层架构
- [算法]数组子数组的最大累乘积
- @using (Html.BeginForm())参数示例
- MyEclipse中Junit使用
- JavaScript内存优化
- jmeter jdbc request使用详解
- 11.UIView的transform属性
- 白话空间统计二十:相似性搜索(二)
- iOS 蓝牙开发(二)iOS 连接外设的代码实现
- python asyncore
- 获取线程ID
- sqlite数据库在程序打包之前清除所有表中的数据
- hibernate关联映射
- 设计模式-单例
- iOS蓝牙开发(一)蓝牙相关基础知识
- 自定义流程节点View
- 一个简单的web服务器
- 基于上一篇的模块化思路,巩固个小知识点——构造函数与原型模式
- opencl hsl 和 rgba 转换
- 【数据结构】二维数组中的查找