CLR via C#(第3版):事件学习(二)显示实现事件

(一)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 Dictionary<EventKey, Delegate> m_events = new Dictionary<EventKey, Delegate>();
        //如果一个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 EventHandler<FooEventArgs> Foo
        {
            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...");
           
        }
    }
}

 代码下载

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值