(一)EventKey
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace EventDemo2{ public sealed class EventKey : Object { }}
(二)EventSet
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace EventDemo2{ //显示实现事件 //原因:因为Winform,WPF,Asp.Net提供了约70个事件,但程序员大多用不到。为了高效存储事件委托 //FCL中System.ComponetModel.EventHandlerList(链表且无线程安全)和这里的EventSet类一样的作用 public sealed class EventSet { //私有字典用于维护EvnentKey->Delegate映射 private readonly Dictionarym_events = new Dictionary (); //如果一个EvnentKey->Delegate映射(如果EventKey不存在) //或者将一个委托与一个实现的EventKey合并 public void add(EventKey eventKey,Delegate handler) { Monitor.Enter(m_events); Delegate d; m_events.TryGetValue(eventKey,out d); m_events[eventKey]=Delegate.Combine(d,handler); Monitor.Exit(m_events); } //从EventKey(如果存在)删除一个委托,并且 //在删除最后一个委托时删除EventKey->Delegate映射 public void Remove(EventKey eventKey,Delegate handler) { Monitor.Enter(m_events); Delegate d; //调用TryGetValue,确保在尝试从集合中删除一个不存在的EventKey //不会抛出异常 if(m_events.TryGetValue(eventKey,out d)) { d=Delegate.Remove(d,handler); //如果还有委托,就设置新的头部(地址)否者删除EventKey if(d!=null)m_events[eventKey]=d; else m_events.Remove(eventKey); } Monitor.Exit(m_events); } //为指定的EventKey引发事件 public void Raise(EventKey eventKey,Object sender,EventArgs e) { Delegate d; Monitor.Enter(m_events); m_events.TryGetValue(eventKey,out d); Monitor.Exit(m_events); if(d!=null) { //由于字典可能包含几个不同的委托类型 //所以无法再编译是构造一个安全的委托调用 //因此,我调用System.Delegate类型的DynamicInvoke //方法,以一个对象数组的形式向它传递回调方法的参数 //在内部,DynamickInvoke会调用的回调方法查证参数的类型安全,并调用方法 //如果存在类型不匹配的情况,DynamicInvoke会抛出一个异常 d.DynamicInvoke(new Object[]{sender,e}); } } }}
(三)FooEventArgs
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace EventDemo2{ public class FooEventArgs:EventArgs{} }
(四)TypeWithLotsOfEvents
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace EventDemo2{ public class TypeWithLotsOfEvents { private readonly EventSet m_eventSet = new EventSet(); protected EventSet EventSet { get { return m_eventSet; } } //构造一个静态只读对象来标识这个事件 //每个对象都有他自己的哈希码,以便对象的集合中查找到这个事件的委托链表 protected static readonly EventKey s_tooEventKey = new EventKey(); //定义事件的访问器方法,用于在集合中增删委托 public event EventHandlerFoo { add { m_eventSet.add(s_tooEventKey, value); } remove { m_eventSet.Remove(s_tooEventKey, value); } } protected virtual void OnFoo(FooEventArgs e) { m_eventSet.Raise(s_tooEventKey, this, e); } //定义将输入转换成这个事件的方法 public void SimulateFoo() { OnFoo(new FooEventArgs()); } }}
(五)代码调用
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace EventDemo2{ class Program { static void Main(string[] args) { TypeWithLotsOfEvents twle = new TypeWithLotsOfEvents(); twle.Foo += HandleFooEvent; //触发事件 twle.SimulateFoo(); Console.ReadKey(); } private static void HandleFooEvent(object sender, FooEventArgs e) { Console.WriteLine("Handling Foo Event here..."); } }}