事件处理时组件设计中相当重要的一环,在C#事件与delegate是紧密相关的,下面是一个简单的事件范例。
1-1
using System; namespace EventDemo { public delegate void ProcessHander(object sender); public class Class1 { private event ProcessHandler processHandler = null; public event ProcessHandler ProcessStart { add{ processHandler +=value; } remove{ processHandler -=value; } } public void Process() { processHander(this); for(int i=0;i<10;i++) { i=i+1; } } public Class1(){} } }
C#之中的delegate扮演者函数指针的角色,用户可以将某个函数加入一个delegate之中,而一个delegate允许用户加入一个以上的函数,当调用此delegate时就等同于调用其内所含的所有函数。不过程序的设计手法潜藏着一个问题,就是当事件数众多时,对象就必须付出相应数量的delegate变量,如下面程序:
1-2
private event ProcessHandler processStart = null; private event ProcessHandler processEnd =null; private event ProcessHandler ProcessStep =null;
不管用户是否用到了这些事件,当对象被创建起来时就得付出这些成本,这在窗口应用程序上更显得可怕,因为Window Message(窗口消息)的数量以千为单位,假如一个简单的窗口程序就必须付出相对于Windows Message数量的变量成本,这样一来对象岂不成了庞然大物了。
针对这个问题,.net framework采取了与Lazy-Allocate类似的方式来处理,如下面程序
public class Class1 { private Hashtable eventList = new Hashtable(); private static object processStart = new object(); private static object processEnd = new object(); public event ProcessHandler ProcessStart { add{ eventList.Add(processStart,value); } remove{ eventList.Remove(processStart); } } public event ProcessHandler ProcessEnd { add{ eventList.Add(processEnd,value); } remove{ eventList.Remove(processEnd); } } public void Process() { ProcessHandler start = (ProcessHandler)eventList[processStart]; ProcessHnadler end = (ProcessHandler)eventList[processEnd]; if(start!=null) start(this); for(int i =0 ;i<10;i++) { i = i+1; } if(end!=null) end(this); } }
程序中声明了一个Hashtable类型的对象:eventList,每一个Class1类的实体都拥有这个对象,另外还声明了两个objec类型的对象:processStart、processEnd,注意!这两个对象是static(静态)类型,也就是说,不管有多少个对象实体,都只须花费两个object的空间。那这段代码与上面的做法有何不同呢?答案是对象所占的内存大小不同,当用户创建一个对象实体后,此对象占用了一个Hashtable对象的内存空间,在用户设定了ProcessStart事件时,此对象随之占用了一个Hashtable元素的内存空间,若用户未设定事件,那么次元素的内存空间就不会被占用,相较于前面范例的预付行为,此方式可以省下不必要付出的内存成本。再详细点说,假设Class1拥有1000个事件,那么程序1-2的做法在对象创建初期就会占用1000个event变量的内存空间,而程序1-3则要付出一个Hashtable对象及1000个static变量的代价,当用户创建第二个对象时,程序1-2要再次占用了1000个event变量的代价,但程序1-3只须占用一个hashtable对象的代价,优劣立见不是吗?很幸运,这种设计概念在.net
framework中已提供了基础建设,设计人员要套用即可,见下面程序1-4:
public class Componet1:Componet { private static object processStart = new object(); public event EventHandler ProcessStart { add{ Events.AddHandler(processStart,value); } remove{ Events.RemoveHandler(processStart,value); } } public void Process() { EventHandler handler = (EvnetHandler)Events[processStart]; if(handler !=null) handler(this,null); } }
只要继承自Component类或其子类就可以使用这种方式来处理事件。