C#事件与委托的区别
C#事件与委托的区别
1. 委托
事件是利用委托来定义的,因此先解释委托。委托是一个类,它与其他类如int,string等没有本质区别,int代表的是所有的整形,而string代表的是字符串,委托则代表的是一类方法,这类方法具有相同返回类型和相同参数。委托的定义:
public delegate void CalculatorHandler(int x,int y);
从CalculatorHandler这个委托的定义可以看出,它反应的是一类方法,这类方法的返回类型是void,两个参数是(int x,int y),因此以后所有具有这样特征的方法都可以用这个委托来代替,现有以下这个方法:
static void Add(int x, int y)
{
Console.WriteLine("x+y={0}",x+y);
}
首先要将这个方法赋值给这个委托才可以使用,就如普通的类赋值一样,
CalculatorHandler calhandler = new CalculatorHandler(Add)
当然你也可以像给一个整形赋值一样,这样赋值:
CalculatorHandler calhander = Add;
当要调用这个方法的时候,你可以就像使用方法一样使用委托,
calhander(3,4);
委托也可以绑定多个方法,当调用这个委托时,会调用所有已经绑定了的方法,如现在还有这样的方法:
static void Multiply(int x, int y)
{
Console.WriteLine("x*y={0}",x*y);
}
只需在calhandler基础上多绑定个方法,具体语法:
calhander += Multiply;
这样当调用
calhander(3,4);
会同时调用Add和Multiply这两个方法,你也可以利用“-=”解绑方法:
calhander -= Multiply;
这样再次调用这个委托,则只会调用Add这个方法。
2. 事件
一说到事件总会有发布者(publisher)和订阅者(subscriber),发布者定义了一个事件,订阅者订阅了该事件(指的是当该事件触发时,订阅者做出什么样的反应,即利用相应的函数去处理)。该函数的定义与定义该事件的委托配套。代码如下:

public delegate void MessageEventHandler();
class Publisher
{
public event MessageEventHandler MessageEvent;
public void DoSomething()
{
Console.WriteLine("等待消息");
Console.WriteLine("首长来啦!!!");
OnMessageEvent();
}
public void OnMessageEvent()
{
if (MessageEvent != null)
{
MessageEvent();
}
}
}
class Subscriber
{
public Subscriber(Publisher p)
{
p.MessageEvent += Response;
} public void Response()
{
Console.WriteLine("首场,辛苦了");
}
} class Program
{
static void Main(string[] args)
{
Publisher p = new Publisher();
Subscriber s = new Subscriber(p);
p.DoSomething();
Console.ReadKey();
}
}
}

这就是事件的基本用法,但是事件与委托到底有什么区别呢,从上面的代码可以看出,事件是根据委托来定义的,
public event MessageEventHandler MessageEvent
其实它是利用委托来规定订阅者处理函数的类型(相同的返回类型和参数即为一类),然后可以方便在发布者自身的类中来触发订阅者的一些方法。
但是为什么要事件呢,要实现这些,我仅用委托也可以实现呀,如下代码:

public delegate void MessageEventHandler();
class Publisher
{
public MessageEventHandler MessageEvent;//为了方便,委托名与原来的事件名相同。
// public event MessageEventHandler MessageEvent;
public void DoSomething()
{
Console.WriteLine("等待消息");
Console.WriteLine("首长来啦!!!");
OnMessageEvent();
}
public void OnMessageEvent()
{
if (MessageEvent != null)
{
MessageEvent();
}
}
}
class Subscriber
{
public Subscriber(Publisher p)
{
p.MessageEvent += Response;
} public void Response()
{
Console.WriteLine("首场,辛苦了");
}
}
class Program
{
static void Main(string[] args)
{
Publisher p = new Publisher();
Subscriber s = new Subscriber(p);
p.DoSomething();
Console.ReadKey();
}
}

这样子也同样可以产生相同的结果。
但是当客户端如下调用呢?
Publisher p = new Publisher();
Subscriber s = new Subscriber(p);
p.DoSomething();
p.MessageEvent();
Console.ReadKey();
客户端是不是能随意让发布者产生事件,因此我们可否将发布者的委托定义为private,因为只有发布者的内部才能触发事件嘛,其他人怎么可以?但是这样订阅者就无法订阅了,那我们是否可以增加绑定可解除的函数来订阅此委托呢?

public delegate void MessageEventHandler();
class Publisher
{
private MessageEventHandler MessageEvent;
// public event MessageEventHandler MessageEvent;
public void DoSomething()
{
Console.WriteLine("等待消息");
Console.WriteLine("首长来啦!!!");
OnMessageEvent();
}
public void OnMessageEvent()
{
if (MessageEvent != null)
{
MessageEvent();
}
}
public void Add_MessageEvent(MessageEventHandler m)
{
MessageEvent += m;
}
public void Reomove_MessageEvent(MessageEventHandler m)
{
MessageEvent -= m;
}
}
class Subscriber
{
public Subscriber(Publisher p)
{
//p.MessageEvent += Response;
p.Add_MessageEvent(Response);
} public void Response()
{
Console.WriteLine("首场,辛苦了");
}
}
class Program
{
static void Main(string[] args)
{
Publisher p = new Publisher();
Subscriber s = new Subscriber(p);
p.DoSomething();
Console.ReadKey();
}
}
}

这样就可以实现与事件一样的功能,因此为了方便微软为我们提供了事件访问器,何为事件访问器?

public delegate void MessageEventHandler();
class Publisher
{
private MessageEventHandler MessageEvent;
// public event MessageEventHandler MessageEvent; public event MessageEventHandler TestEvent
{
add
{
lock (MessageEvent)
{
MessageEvent += value;
}
}
remove
{
lock (MessageEvent)
{
MessageEvent -= value;
} }
}
public void DoSomething()
{
Console.WriteLine("等待消息");
Console.WriteLine("首长来啦!!!");
OnMessageEvent();
}
public void OnMessageEvent()
{
if (MessageEvent != null)
{
MessageEvent();
}
} }
class Subscriber
{
public Subscriber(Publisher p)
{
p.TestEvent += Response; } public void Response()
{
Console.WriteLine("首场,辛苦了");
}
}
class Program
{
static void Main(string[] args)
{
Publisher p = new Publisher();
Subscriber s = new Subscriber(p);
p.DoSomething();
Console.ReadKey();
}
}

以上的代码就是利用事件访问器来让委托绑定订阅者的方法,事件访问器中的add和remove能自动编译为+=和-=。
通过reflector,我们可以看到一个事件是如何定义的:

它是申明一个私有的委托:
private MessageEventHandler MessageEvent;
另外利用两个函数来绑定与解除订阅者的方法。
C#事件与委托的区别的更多相关文章
- C# 事件和委托
相信大家在面试的时候会经常问到事件和委托的区别,为什么.net中需要事件和委托这样类似的问题吧,对于一些初学者来说可平时用的过程中也不知道为什么, 只知道这样用,而对于其中的实现机制不是很清楚, 所以 ...
- 事件、委托、委托方法的总结(使用EventHandler<>)
在C#中,定义事件.委托.委托方法可以使用类库内的EventHandler泛型委托来定义事件.并根据该泛型委托定义实现方法: 同样您也可以自定义委托 来定义事件以及 根据自定义的委托来定义实现事件的方 ...
- C#基础精华07(委托事件,委托的使用,匿名方法)
1.委托概述 委托是一种数据类型,像类一样(可以声明委托类型变量).方法参数可以是int.string.类类型 void M1(int n){ } √ void M2(string s){ } √ ...
- [C#参考]事件和委托的关系
前面说了委托,接下来就要说一说事件了,同时最后再说一下委托和事件的区别. 事件和委托很相似,事件就好像是被简化的针对特殊用途的委托.看下面的图: 从这张图中能看到,事件是发布者的一个成员,它不是类型. ...
- C#事件与委托详解【精华 多看看】
Delegate delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类.与其它的类不同,delegate类能够拥有一个签名(signature),并且它"只能持有与 ...
- C#基础知识之事件和委托
本文中,我将通过两个范例由浅入深地讲述什么是委托.为什么要使用委托.委托的调用方式.事件的由来..Net Framework中的委托和事件.委托和事件对Observer设计模式的意义,对它们的中间代码 ...
- 解密jQuery事件核心 - 委托设计(二)
第一篇 http://www.cnblogs.com/aaronjs/p/3444874.html 从上章就能得出几个信息: 事件信息都存储在数据缓存中 对于没有特殊事件特有监听方法和普通事件都用ad ...
- c#事件与委托
C#.net 目录(?)[-] 将方法作为方法的参数 将方法绑定到委托 事件的由来 事件和委托的编译代码 委托事件与Observer设计模式 范例说明 Observer设计模式简介 实现范例的Obse ...
- 《C#高级编程》学习笔记------C#中的事件和委托
本文转载自张子阳 目录 委托的作用 将方法绑定到委托 事件的来由 Observer设计模式 .Net Framework中的委托与事件 引言 委托 和 事件在 .Net Framework中的应用 ...
随机推荐
- PHP MVC自己主动RBAC自己主动生成的访问路由
使用的关键点: ReflectionClass class Rbac extends MY_Controller { public function index() { $arr = glob( __ ...
- unity 编辑器和插件生产(四.2)
上次 我们告诉编辑器制作,如何将图像加载到现场,如今 我们要告诉下.怎么样 制造UIButton以及UIimage交换. 阿土. 进入专题. 首先,我们要明白 unity机制.button属性等. 首 ...
- javascript中常用坐标属性offset、scroll、client
原文:javascript中常用坐标属性offset.scroll.client 今天在学习js的时候觉得这个问题比较容易搞混,所以自己画了一个简单的图,并且用js控制台里面输出测试了下,便于理解. ...
- 至linuxNIC添加多个IP
由于工作的需要,只是有一个2以太网端口server构造3个月IP.制linux. 整理如以下的现在的过程,有离开后,,学生们也将不能够引用. IP1:10.110.97.68 IP2:10.115.2 ...
- Tsql查询执行顺序
对于T-SQL编程,用得最广泛的,莫过于查询(Querying).要想写出高质量.高性能的查询语句,必须深入地了解逻辑查询处理. 一.逻辑查询处理的各个阶段 (5)SELECT DISTINCT TO ...
- 至尊快速,国产语言RPP 1.83强势来袭
以下是 R++的性能測试数据:(奔腾 1.86GHZ,測试 3 次取平均值) 执行效率: R++的内部结构和 C++大致同样,所以理论上 R++能够达到和 C++一样的执行速度,眼下 R++已开启汇编 ...
- Swift中文教程(五)--对象和类
原文:Swift中文教程(五)--对象和类 Class 类 在Swift中可以用class关键字后跟类名创建一个类.在类里,一个属性的声明写法同一个常量或变量的声明写法一样,除非这个属性是在类的上下文 ...
- svnclient本地化和异常处理
svn中国本土化,首次安装client.然后下载语言包的相应版本,然后将语言设置为英文! 我碰到汉化失败的案例:client与语言包版本号不匹配 之前安装的语言包: 下载相应语言包: 假设之前安装了, ...
- IIS 7.5 使用URL Rewrite模块简单设置网页跳转
原文 IIS 7.5 使用URL Rewrite模块简单设置网页跳转 我们都知道Apache可以在配置文件里方便的设置针对网页或网站的rewrite,但是最近接手了一组IIS服务器,发现这货简单的没有 ...
- 搭建及修正Hadoop1.2.1 MapReduce Pipes C++开发环境
Hadoop目前人气超旺,返璞归真的KV理念让人们再一次换一个角度来冷静思考一些问题. 但随着近些年来写C/C++的人越来越少,网上和官方WIKI的教程直接落地的成功率却不高,多少会碰到这样那样的问题 ...