最近项目中需要用到异步编程,虽然以前研究过,但时间一长竟然就都忘了于是就又再重新学习了一遍……
首先引用MSDN中的一段话来描述一下如何使用异步方式:
.NET Framework 允许您异步调用任何方法。 为此,应定义与您要调用的方法具有相同签名的委托;公共语言运行时会自动使用适当的签名为该委托定义 BeginInvoke 和 EndInvoke 方法。
BeginInvoke 方法启动异步调用。 该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。 第一个参数是一个AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。 第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。 BeginInvoke 立即返回,不等待异步调用完成。 BeginInvoke 返回一个IAsyncResult,后者可用于监视异步调用的进度。
EndInvoke 方法检索异步调用的结果。 在调用 BeginInvoke 之后随时可以调用该方法。 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成。 EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。
(点此处获取更多介绍)
如果上面的介绍不明白,没有关系,下面我将通过一个简单的例子来进行演示。
先看一下程序主界面图,以便后面的代码说明较好理解:
从中可以看出,老黄可以同时烧开水和看电视,这就是异步。下面给出老黄类的定义:
public class LaoHuang { //定义委托 private delegate void BoilWaterDelegate(); //声明委托变量 BoilWaterDelegate boilwaterDelegate; /// <summary> /// 看电视 /// </summary> public void WatchTV() { } /// <summary> /// 烧水 /// </summary> public void BoilWater() { //模拟烧水的过程 Thread.Sleep(5000); } public IAsyncResult BeginBoilWater(Action call) { boilwaterDelegate = new BoilWaterDelegate(BoilWater); IAsyncResult result = boilwaterDelegate.BeginInvoke(new AsyncCallback(CallBack), call); return result; } public void EndBoilWater(IAsyncResult result) { boilwaterDelegate.EndInvoke(result); } /// <summary> /// 回调函数 /// </summary> private void CallBack(IAsyncResult result) { Action call = result.AsyncState as Action; EndBoilWater(result); call(); } }
然后,给出界面中的代码:
private void button_Click(object sender, EventArgs e) { LaoHuang laohuang = new LaoHuang(); resultTextbox.AppendText(GetTime()+"老黄想喝茶了……\r\n"); laohuang.BeginBoilWater(ActionCallBack); resultTextbox.AppendText(GetTime()+"老黄开始烧水……\r\n"); laohuang.WatchTV(); resultTextbox.AppendText(GetTime() + "老黄打开了电视……\r\n"); } private void ActionCallBack() { //MethodInvoker 表示一个委托,该委托可执行托管代码中声明为 void 且不接受任何参数的任何方法 resultTextbox.Invoke((MethodInvoker)(() => { resultTextbox.AppendText(GetTime() + "水烧开了,老黄泡好了茶……\r\n"); resultTextbox.AppendText(GetTime() + "老黄可以一边喝茶,一边看电视了……\r\n"); })); } private string GetTime() { return DateTime.Now.ToLongTimeString()+"->"; }