细节:关于异步调用的解决方案
来说明如何处理后台线程通过异步方式来更新UI。他的方案非常棒,但是客户端稍稍复杂了一点,在非常复杂的场景可能会发生问题。我在实际工作中遇到这个问题的时候不是以异步委托的面目出现的,而是以接口方式实现的,这样的情况更具有一般性。我通常是在若干个订阅端(Subscriber)实现这个“订阅主题”的接口,在一个发布端(Publisher)实现同样一个接口,并提供对订阅者的管理。事实上,在业务层实现这个发布端的接口是容易的,但在GUI的订阅端有可能会发生另外一些问题,例如如果业务端与GUI客户端并不在同一个线程中。典型的例子就是通常将“长任务”放到某个后台线程中去执行,在执行过程中可以在任何时候将执行状态报告给前台线程。显然,这是一个处理一般性Observe模式的通用方案。
实现的方法有点变态,和Mixin的原理很相似。在一个AsyncObjectBase的基类或者该基类的派生类上动态实现客户端接口,同时实现对订阅者的管理。之所以动态化是为了适应客户端接口中的任何签名的方法。
以下是关于AsyncObjectBase的简单的API:
提供了两个方法来管理订阅者:
Register(object):添加订阅者。
Unregister(object):删除订阅者。
提供了三个方法来管理发布状态:
Disable():关闭发布。
Enable(object):仅开放指定的订阅者。
Enable():开放所有的订阅者。
提供了两个静态方法来实例化接口的服务端实现:
AsyncObjectBase GetObject(Type, Type):获取指定基类、指定接口类型的服务端实现(指定基类必须继承自AsyncObjectBase)。
AsyncObjectBase GetObject(Type):获取指定接口类型的服务端实现。
从AsyncObjectBase派生一个自定义类型来重写委托指派方法可实现复杂的委托(不仅限于基于System.Windows.Form.Control的实现类)。这三个方法是:
void CheckDelegate(Delegate, object[], out bool);
object ChecjDelegate2(Delegate, object[], out bool);
以上两个方法都是捕获委托的,差异是前者实现的委托无返回值,而后者实现的委托有返回值。最后一个参数通知服务器该委托是否已经被捕获,以决定是否需要继续raise这个委托。这是本方案加入自定义委托捕获的唯一途径。
bool GetEnabled(object):返回是否需要向指定委托者发布。
示例实现这样一个场景:后台线程打开一个文本文件,然后一段一段地向多个订阅者发布。
有两点需要说明:
一、示例未实现多接口,当然如果需要的话,改造过程非常简单。
二、未处理带返回值的方法的接口,当然如果需要的话,改造过程也非常简单。