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#事件与委托的区别的更多相关文章

  1. C# 事件和委托

    相信大家在面试的时候会经常问到事件和委托的区别,为什么.net中需要事件和委托这样类似的问题吧,对于一些初学者来说可平时用的过程中也不知道为什么, 只知道这样用,而对于其中的实现机制不是很清楚, 所以 ...

  2. 事件、委托、委托方法的总结(使用EventHandler<>)

    在C#中,定义事件.委托.委托方法可以使用类库内的EventHandler泛型委托来定义事件.并根据该泛型委托定义实现方法: 同样您也可以自定义委托 来定义事件以及 根据自定义的委托来定义实现事件的方 ...

  3. C#基础精华07(委托事件,委托的使用,匿名方法)

    1.委托概述 委托是一种数据类型,像类一样(可以声明委托类型变量).方法参数可以是int.string.类类型 void M1(int n){  } √ void M2(string s){  } √ ...

  4. [C#参考]事件和委托的关系

    前面说了委托,接下来就要说一说事件了,同时最后再说一下委托和事件的区别. 事件和委托很相似,事件就好像是被简化的针对特殊用途的委托.看下面的图: 从这张图中能看到,事件是发布者的一个成员,它不是类型. ...

  5. C#事件与委托详解【精华 多看看】

    Delegate delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类.与其它的类不同,delegate类能够拥有一个签名(signature),并且它"只能持有与 ...

  6. C#基础知识之事件和委托

    本文中,我将通过两个范例由浅入深地讲述什么是委托.为什么要使用委托.委托的调用方式.事件的由来..Net Framework中的委托和事件.委托和事件对Observer设计模式的意义,对它们的中间代码 ...

  7. 解密jQuery事件核心 - 委托设计(二)

    第一篇 http://www.cnblogs.com/aaronjs/p/3444874.html 从上章就能得出几个信息: 事件信息都存储在数据缓存中 对于没有特殊事件特有监听方法和普通事件都用ad ...

  8. c#事件与委托

    C#.net 目录(?)[-] 将方法作为方法的参数 将方法绑定到委托 事件的由来 事件和委托的编译代码 委托事件与Observer设计模式 范例说明 Observer设计模式简介 实现范例的Obse ...

  9. 《C#高级编程》学习笔记------C#中的事件和委托

    本文转载自张子阳 目录 委托的作用 将方法绑定到委托 事件的来由 Observer设计模式 .Net Framework中的委托与事件   引言 委托 和 事件在 .Net Framework中的应用 ...

随机推荐

  1. 2014ACM/ICPC亚洲区域赛牡丹江站汇总

    球队内线我也总水平,这所学校得到了前所未有的8地方,因为只有两个少年队.因此,我们13并且可以被分配到的地方,因为13和非常大的数目.据领队谁oj在之上a谁去让更多的冠军.我和tyh,sxk,doub ...

  2. Android经常使用的布局类整理(一)

    Android经常使用的布局类整理 近期又回头做了一下android的项目,发觉越来越不从心,非常多东西都忘了,简单的页面布局也非常多写不出来,首先还是先整理一下一些会混淆的概念先 layout_wi ...

  3. 当<script>中的type等于text/html的妙用

    我们可以在<script>片断中定义一个被JS调用的代码,但代码又不在页面上显示,这时,我们可以使用下面的方法: <script id="commentTemplate&q ...

  4. sql server 汉字的长度

    前几天改了人家程序中的一个小bug,就是输入时长度的校验问题.项目是.Net的,数据库是 sql server的.检查了一下,发现以前的人员把长度给控制小了,数据库中允许输入256的长度,而别人在as ...

  5. 【Swift】 GET&POST请求 网络缓存的简单处理

     GET & POST 的对比 源码:https://github.com/SpongeBob-GitHub/Get-Post.git 1. URL - GET 所有的参数都包含在 URL 中 ...

  6. php_linux_ubuntu_安装mysql_apache_php

    用apt-get方法安装mysql5 + Apache2 + PHP5+Phpmyadmin [建议] http://www.sudu.cn/info/html/edu/20080102/283439 ...

  7. linux_ubuntu12.04 卸载和安装mysql、远程访问、not allowed

    一: 安装mysql 卸载mysql 第一步 sudo apt-get autoremove --purge mysql-server-5.0 sudo apt-get remove mysql-se ...

  8. 类别sort使用排序

    2129: 船上的第二次测试第三个问题 Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 243  Solved: 74 [Submit][id=2129 ...

  9. [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系

    原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...

  10. Oracle 免费的数据库

    Oracle 免费的数据库--Database 快捷版 11g 安装使用与"SOD框架"对Oracle的CodeFirst支持 一.Oracle XE 数据库与连接工具安装使用 O ...