C# 事件系统(一)

  每次过年在家的时候,都想着挖点坑.但是每次年后工作忙起来就在没填过.今年照例挖坑.希望年后自己能填平.

  先说下事件.首先事件并不是局限的说那个关键字event.而是说这个需求实现的动作或者方向.当然这句表达的可能不太清楚.下面我会举几个例子.

我们先想这样一种场景.我们某个业务会一直运算处理一些数据,这时我们想暴露一些处理的状态给外部,比如说处理完成了一批数据或者已经没有数据可以处理的这种状态.我们当然可以把这种状态设置给某个属性上暴露出来,但是这里会出现一个问题.就是外部应该在什么时候访问这个属性.

  这种场景很常见.比如你抢票的时候,订单已经提交了.当没有余票给你的时候,无论你怎么刷新页面也不会有新的状态给你.或者当你后台下载大文件的时候.不论你多久看一眼是否下载完成.都很难看一次就知道已经完成了.上面说的场景其实就是轮询.通过不断访问来确定当前的状态.那么最好的方式应该是当状态改变时有某个机制通知我完成了.比如你抢票成功了有短信提醒,下载完成时有叮的一声提示.

  通过上面的例子,我们自然会想到.当业务运行到某处需要通知外部时,调用一个方法通知外部即可.这也就是说事件其实是数据传递的一种方式.他是有方向的,由内部主动传递到外部.

  上面说道用一个方法通知外部,那么这个方法一定是外部的方法.在C#中当我们需要传递一个方法的时候,自然会想到Action,Func什么的,这些都是委托的一种包装.这么看来那个event关键字就很容易理解了,通过这个关键字.我们对外暴露一个特殊的属性.通过这个属性,我们可以传递或者移除一个委托给内部.内部通过调用这个事件来间接的调用那些外部方法.

  当然这里面也会说到解耦啊,封装什么的说法.这里我们先不讨论这些.我们要讨论的是如何设计一个系统,让内部与外部传递数据变得更简介更方便.那言归正传,事件系统肯定是先要有事件,我们先抽象一个事件基类.先上代码.

    /// <summary>
    /// 事件方法
    /// </summary>
    public abstract class EventMethod
    {
        #region Field
        /// <summary>
        /// 事件句柄
        /// </summary>
        private string handle;
        #endregion

        #region Property
        /// <summary>
        /// 事件句柄
        /// </summary>
        public string Handle { get => handle; }
        #endregion

        #region Construction
        /// <summary>
        /// 创建一个 EventMethod 类新实例
        /// </summary>
        public EventMethod() => handle = GetHandle();
        #endregion

        #region Method
        /// <summary>
        /// 获取绑定的事件句柄
        /// </summary>
        protected virtual string GetHandle() => GetType().Name;
        /// <summary>
        /// 唤醒事件
        /// </summary>
        internal abstract void Awake(params object[] parameters);
        #endregion
    }

   事件句柄是为了在事件容器内获取的事件的一个Key.这里主要的是Awake方法.当系统触发某个事件时,会在容器中通过Kye将全部的事件方法获取出来,依次调用Awake方法.事件参数不确定,所以这里Awake参数是params的.其他具体的事件通过重写Awake来进行重新重构.下面我们就重构一个按钮单击事件作为例子.

    /// <summary>
    /// 按钮单击事件
    /// </summary>
    public class BtnClick : EventMethod
    {
        #region Field
        /// <summary>
        /// 回调委托
        /// </summary>
        private Action action;
        #endregion

        #region Construction
        /// <summary>
        /// 创建一个 BtnClick 类新实例
        /// </summary>
        public BtnClick(Action action) => this.action = action;
        #endregion

        #region Method
        /// <summary>
        /// 唤醒事件
        /// </summary>
        /// <param name="parameters"></param>
        internal override void Awake(params object[] parameters) => action?.Invoke();
        #endregion
    }

  以上,我们就完成了一个事件的设计.其他部分我们在后面的文章讨论

猜你喜欢

转载自www.cnblogs.com/kent-apple/p/12238977.html