委托类有两个方法, 叫做BeginInvoke和EndInvoke
当我们调用委托的BeginInvoke方法时,它开始在线程池中的独立线程上执行引用方法,并且立即返回原始线程, 原始线程可以继续, 而引用方法会在线程池的线程中并行执行
当程序希望获取已完成的异步方法的结果时, 可以检查BeginInvoke返回的IAsyncResult的IsCompleted属性, 或调用委托的EndInvoke方法来等待委托完成.
在 等待--直到完成 模式中,在发起了异步方法以及做了一些其他处理之后,原始线程就中断并且等异步方法完成之后再继续
在 轮询 模式中, 原始线程定期检查发起的线程是否完成, 如果没有则可以继续做一些其他的事情.
在 回调 模式中, 原始线程一直执行, 无需等待或检查发起的线程是否完成 , 在发起的线程中的引用方法完成之后, 发起的线程就会调用回调方法, 有回调方法在调用EndInvoke之前处理异步方法的结构.
在调用BeginInvoke时,参数列表中的实参数组组成如下:
引用方法需要的参数;
两个额外的参数-----callback参数和state参数
BeginInvoke从线程池中获取一个线程并且在新的线程开始时运行引用方法
BeginInvoke返回给调用线程一个实现IAsyncResult接口的对象.这个接口应用包含了异步方法的当前状态, 原始线程然后可以继续执行
之后的行声明了一个叫del的Mydel委托类型的委托对象,并且使用Sum方法来初始化它的调用列表
最后一行代码调用了委托对象的BeginInvoke方法并且提供了两个委托参数3和5, 以及两个BeginInvoke的参数callback和state, 在本例中都设为null. 执行后, BeginInvoke方法进行两个操作:
从线程池中获取一个线程并且在新的线程上开始运行Sum方法,提供它3和5作为参数.
它收集新线程的状态信息并且把IAsyncResult接口的引用返回给调用线程来提供这些数据.
调用线程把它保存在一个叫做iar的变量中.
EndInvoke方法用来获取由异步方法调用返回的值,并且释放线程使用的资源. EndInvoke有如下的特性:
它接受一个由BeginInvoke方法返回的IAsyncResult对象的应用, 并找到它关联的线程.
如果线程池的线程已经退出, EndInvoke做如下的事情:
它清理退出线程的状态并且释放它的资源
它找到引用方法返回的值并且把它的值作为返回值
如果当EndInvoke被调用时线程池的线程仍然在运行,调用线程就会停止并且等待. 直到清理完毕并且返回值. 因为EndInvoke是为开启的线程进行清理, 所以必须确保对每一个BeginInvoke调用EndInvoke.
如果异步方法触发了异常,在调用EndInvoke时会抛出异常.
AsyncResult类
当我们调用委托对象的BeginInvoke方法时,系统创建了一个AsyncResult类的对象. 然而,它不返回类对象的引用. 而是返回对象中包含的IAsyncResult接口的引用.
AsyncResult对象包含一个叫做AsyncDelegate的属性, 它返回一个指向被调用来开启异步方法的委托的引用, 但是, 这个属性是类对象的一部分而不是接口的一部分.
IsCompleted属性返回一个布尔值, 表示异步方法是否完成.
AsyncState属性返回一个对象的引用, 它被作为BeginInvoke方法调用时的state参数. 它返回Object类型的引用
回调模式
在之前的等待---直到结束模式以及轮询模式中, 初始线程继续它自己的控制流程, 直到它知道开启的线程完成, 然后, 它获取结果并继续.
回调模式的不同之处在于, 一旦线程发起了异步方法, 它就自己管自己了, 不再考虑同步. 当异步方法调用结束之后, 系统调用一个用户自定义的方法来处理结果, 并且调用委托的EndInvoke方法.这个用户自定义的方法叫做回调方法或回调.
BeginInvoke的参数列表中最后两个额外参数被回调方法使用:
第一个参数为callback, 是回调方法的名字
第二个参数为state,可以是null护着是要传入回调方法的一个对象的引用,我们可以通过使用IAsyncResult参数的AsyncState属性来获取这个对象,参数的类型为object
给回调方法的参数只有一个, 就是刚结束的异步方法IAsyncResult接口的引用, IAsyncResult接口对象在AsyncResult类对象的内部.
尽管IAsyncResult接口没有委托对象的引用, 而包含它的AsyncResult类对象却有委托对象的引用. 所以, 示例代码方法体的第一行就通过转换接口引用为类类型来获取类对象的引用. 变量ar现在就有类对象的引用.
有了类对象的引用 , 我们现在就可以调用类对象的AsyncDelegate属性并且把它转化为合适的委托类型.,这样就得到了委托引用, 我们可以用它来调用EndInvoke.
其实一开始传入的参数iar就是AsyncResult类型的,只是设为了IAsyncResult类型,后来又转换回来了而已,所以是符合里氏代换原则的