Welcome

首页 / 软件开发 / .NET编程技术 / 说说.net事件和委托

说说.net事件和委托2010-09-24LoveBaoBao一说到.net的事件,也许你会想都说教程满天飞,一个被说烂了的东西还有什么可以说的啊?是啊,的确有很多好文章剖析事件,比如张子阳先生的C# 中的委托和事件

重温Observer模式--热水器·改 这两篇文章让我弄懂了委托、事件和观察者模式的基础知识,另外深入的事件文章还有博客堂 破宝的事件三部曲,(btw 这些都是我看过的,如果你见见过更好的文章请跟帖以便更多人学习,谢谢。:))

现在来说下这个被说烂了的东东我感觉需要注意的地方。

1 单播和多播事件

2 事件的显式定义(继而解释委托和事件的区别)

3 .net事件模型

对于单播和多播事件概念。查资料是这么定义的:单播事件就是对象(类)发出的事件通知,只能被外界的某一个事件处理程序处理,而不能被多个事件处理程序处理,多播事件是对象(类)发出的事件通知,可以同时被外界不同的事件处理程序处理。

说是这么简单,理解清楚不是很简单。有没有想过这里是到底怎么实现的呢?这里我读过《.net框架程序设计》第17.5 委托史话:System.Delegate与system.MulticastDelegate,如果有兴趣可以找来看看,system.MulticastDelegate定义于FCL继承自System.Delegate,这里MulticastDelegate其实就是多播委托,那么多播事件也是通过这个实现的,不用说Delegate大家都可以猜到是单播委托了,那么平时我们定义一个委托public delegate void Back(Object value, Int32 item, Int32 numItems)

当编译器遇到这句委托定义,会产生一个完整的类定义:

public class Back : System.MulticastDelegate
{
public Back(Object target, Int32 methodPtr);
public void virtual Invoke(Object value, Int32 item, Int32 numItems);
public virtual IAsyncResult BeginInvoke(Object vlaue ,Int32. numItems, AsyncCallback callback,Object object);
public virtual void EndInvoke(IAsyncResult result);
}

这个类其内部的方法看不懂没关系,先看这个类的Back是继承自System.MulticastDelegate,也就是说我们平时定义的委托几乎都是继承自多播委托的,那么为什么要有单播委托,这个具《.net框架程序设计》上说是微软.net框架设计的一个缺陷。所以这里大家记住平时定义的委托基本上都是多播的,也就是都可以用+=操作把委托组合成链,这里我不能不说破宝对多播和单播的理解有误。

事件的显式定义,也许你还不知道显式定义是怎么回事,相信很多朋友平时自己定义事件也没注意过这个问题。

回忆下平时我们是怎么定义事件的呢?是不是下面的样子:

classMailManager
{
//定义一个委托类
publicdelegatevoidMailMesgEventHandler(Objectsender,EventArgse);

//定义对应委托的事件
publiceventMailMesgEventHandlerMailMsg;
}

我们需要为事件先定义一个委托类(这里EventArgs我省略没自己定义特定子类),然后用这个委托类型定义事件。

看了很简单,是的,这里就是隐式定义事件,为什么叫隐式呢,我自己弄的名字哈哈,编译这句事件定义代码时要产更多的代码,就像下面这些简化的伪码:

private MailMesgEventHandler MailMesg = null;
public void add_MailMesg(MailMesgEventHandler handler)
{
MailMesg = (MailMesgEventHandler);
Delegate.Combine(MailMsg, handler);
}
public void remove_MailMesg(MailMesgEventHandler handler)
{
MailMesg = (MailMesgEventHandler);
Delegate.Remove(MailMsg, handler);
}
privateMailMesgEventHandlerMailMesg=null;
publicvoidadd_MailMesg(MailMesgEventHandlerhandler)
{
MailMesg=(MailMesgEventHandler);
Delegate.Combine(MailMsg,handler);
}
publicvoidremove_MailMesg(MailMesgEventHandlerhandler)
{
MailMesg=(MailMesgEventHandler);
Delegate.Remove(MailMsg,handler);
}