关于事件的订阅和发布,相信网上已经有很多版本了。基本的原理就是先订阅事件,将订阅的事件保存到特定的容器中,接着,当发布事件的时候,直接调用的保存的事件。
.NET不是已经提供了Event,为什么还要做事件的订阅和发布。
我个人的理解是高度封装自己的事件,这样代码简洁美观,并且易于维护和扩展。
我采用了静态的容器来保存订阅的事件,这样可以跨组建或项目的程序集。
首先我们要定义我们自己的Event事件
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace FYFrameWork.Event { public class FYEventBase<T>:FYEvent { #region << Field >> EventDispathcher eventDispathcher = new EventDispathcher(); #endregion #region << Method >> /// <summary> /// subscribe the event /// </summary> /// <param name="action">subscribe's delegate</param> /// <param name="callMode">subscribe's call function mode</param> public virtual void Subscribe(Action<T> action) { eventDispathcher.AddEvent(new FYWeakReference(action)); } /// <summary> /// publish the event /// </summary> /// <param name="objs">publish's function's parameters</param> public virtual void Publish(CallMode callMode,object objs) { if (callMode == CallMode.SynCall) { ///syn call list of delegate eventDispathcher.GetEvent().ForEach(p => { Application.Current.Dispatcher.Invoke(((Action<T>)(p.GetAction())), (T)objs); }); } else { ///asyn call list of delegate eventDispathcher.GetEvent().ForEach(p => { Application.Current.Dispatcher.BeginInvoke(((Action<T>)(p.GetAction())),(T)objs); }); } } #endregion } }
我们自定义的EventBase 只有两个方法 Subscribe和Publish
Subscribe用来订阅事件(我们这里泛指 无返回值的函数,有返回值的函数我会继续在下个版本加入)
至于FYEvent只是个空的抽象类,就是为了实现EventBase<T>的泛型,有好的办法,大家通知我。
这里我们会看到EventDispathcher类,主要是个List用来村粗Action<T>(无返回函数的委托)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FYFrameWork.Event { public class EventDispathcher { #region << Field >> /// <summary> /// save event dispathcher list /// </summary> private List<FYWeakReference> dispathcherCache = new List<FYWeakReference>(); #endregion #region << Method >> /// <summary> /// add event /// </summary> /// <param name="weakReference">event delegate object</param> public void AddEvent(FYWeakReference weakReference) { if (weakReference == null) throw new Exception("weakReference is null"); var isExist = dispathcherCache.Any((p) => p == weakReference); if (!isExist) { dispathcherCache.Add(weakReference); } } /// <summary> /// remove event /// </summary> /// <param name="weakReference">event delegate object</param> public void RemoveEvent(FYWeakReference weakReference) { if (weakReference != null) { var isExist = dispathcherCache.Any((p) => p == weakReference); if (isExist) dispathcherCache.Remove(weakReference); } } /// <summary> /// get event /// </summary> /// <returns></returns> public List<FYWeakReference> GetEvent() { return dispathcherCache; } #endregion } }
AddEvent就是用来添加Action<T>
在这里又会有FYWeakReference类,就是就是Action<T> 的WeakReference对象。
为什么用WeakReference,用弱引用是尽量的当事件太多时,对于内存的压力。
WeakReference的代码。
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace FYFrameWork.Event { public class FYWeakReference : IFYWeakReference { #region << Field >> private readonly MethodInfo methodInfo; private readonly WeakReference weakReference; private readonly Type actionType; private readonly Delegate action; #endregion #region << Constructor >> public FYWeakReference(Delegate action):this(action,false){} public FYWeakReference(Delegate action, bool isKeepAlive) { if (action == null) throw new Exception("delegate is null"); if (isKeepAlive) { this.action = action; } else { actionType = action.GetType(); weakReference = new WeakReference(action.Target); methodInfo = action.Method; } } #endregion #region << Method >> /// <summary> /// get delegate /// </summary> /// <returns>delegate</returns> public Delegate GetAction() { if (methodInfo.IsStatic) { return Delegate.CreateDelegate(actionType, null, methodInfo); } object obj = weakReference.Target; if (obj != null) return Delegate.CreateDelegate(actionType, obj, methodInfo); return null; } #endregion } }
接着就是我们EventManager.
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FYFrameWork.Event { public interface IFYEventManager { /// <summary> /// get event /// </summary> /// <typeparam name="T">event's type</typeparam> /// <returns>event object</returns> T GetEvent<T>() where T : FYEvent, new(); } }
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FYFrameWork.Event { [Export] public class FYEventManager:IFYEventManager { #region << Field >> private static Dictionary<Type, FYEvent> eventCache = new Dictionary<Type, FYEvent>(); #endregion #region << Method >> /// <summary> /// get the event /// </summary> /// <typeparam name="T">event type</typeparam> /// <returns></returns> public T GetEvent<T>() where T : FYEvent, new() { if (eventCache.ContainsKey(typeof(T))) return (T)eventCache[typeof(T)]; else { T tmpEvent = new T(); eventCache.Add(typeof(T), tmpEvent); return tmpEvent; } } #endregion } }
这EventManager我用字典来存储我们自定义的事件。
GetEvent<T> 泛型来取得对应的事件对象,来进行订阅和发布。
整个订阅和发布,其实就是先存储Event,再调用Event对应的Action<T>
目前这个事件小框架,还不太完善,先发出来,大家讨论下,希望你们也可以发布自己的事件订阅和发布框架。