C# 事件系统(一)
每次过年在家的时候,都想着挖点坑.但是每次年后工作忙起来就在没填过.今年照例挖坑.希望年后自己能填平.
先说下事件.首先事件并不是局限的说那个关键字event.而是说这个需求实现的动作或者方向.当然这句表达的可能不太清楚.下面我会举几个例子.
我们先想这样一种场景.我们某个业务会一直运算处理一些数据,这时我们想暴露一些处理的状态给外部,比如说处理完成了一批数据或者已经没有数据可以处理的这种状态.我们当然可以把这种状态设置给某个属性上暴露出来,但是这里会出现一个问题.就是外部应该在什么时候访问这个属性.
这种场景很常见.比如你抢票的时候,订单已经提交了.当没有余票给你的时候,无论你怎么刷新页面也不会有新的状态给你.或者当你后台下载大文件的时候.不论你多久看一眼是否下载完成.都很难看一次就知道已经完成了.上面说的场景其实就是轮询.通过不断访问来确定当前的状态.那么最好的方式应该是当状态改变时有某个机制通知我完成了.比如你抢票成功了有短信提醒,下载完成时有叮的一声提示.
通过上面的例子,我们自然会想到.当业务运行到某处需要通知外部时,调用一个方法通知外部即可.这也就是说事件其实是数据或状态传递的一种方式.他是有方向的,由内部主动传递到外部.
上面说道用一个方法通知外部,那么这个方法一定是外部的方法.在C#中当我们需要传递一个方法的时候,自然会想到Action,Func什么的,这些都是一种委托.这么看来那个event关键字就很容易理解了,通过这个关键字.我们对外暴露一个特殊的属性.通过这个属性,我们可以传递或者移除一个委托给内部.内部通过调用这个事件来间接的调用那些外部方法.
如果让我们设计一个事件的话,那么肯定是有一个容器,用来存储多个委托.在用另外一个"东西"代表这个事件.当我们想触发某个事件的,只需要通过那个"东西"来获取那个东西代表的集合.然后依次调用委托即可.容器很好实现,C#内置的容器完全满足我们的需求.这里我选择的是HashSet而不是List.因为我的场景下有大量的插入与移除.List这种有序的集合在性能上不太适合.
容器有了,那么那个"东西"我们就很好表示了.我们可以选择任意一种数据来代替.比如int,enum,string等等.我在这里选择的是string.主要因为懒.....当然也有其他的理由.使用Int没有可读性,当你想触发一个事件时很难记起哪个数字是代表这个事件的.使用enum时每增加一个事件都要重新编辑一下enum.当然使用string也不是没有坏处,就是如果你手误了也不会有任何错误的提示.这个就需要跑测试或者通过其他的机制来规避了.
以上扯了那么多,主要是为了阐明需求以及设计.后面会依次实现.
传送门: