C#使用委托进行异步编程
2014-02-23 23:23
183 查看
最近项目中需要用到异步编程,虽然以前研究过,但时间一长竟然就都忘了
于是就又再重新学习了一遍……
首先引用MSDN中的一段话来描述一下如何使用异步方式:
.NET Framework 允许您异步调用任何方法。 为此,应定义与您要调用的方法具有相同签名的委托;公共语言运行时会自动使用适当的签名为该委托定义 BeginInvoke 和 EndInvoke
方法。
BeginInvoke 方法启动异步调用。 该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。 第一个参数是一个AsyncCallback
委托,该委托引用在异步调用完成时要调用的方法。 第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。 BeginInvoke 立即返回,不等待异步调用完成。 BeginInvoke 返回一个IAsyncResult,后者可用于监视异步调用的进度。
EndInvoke 方法检索异步调用的结果。 在调用 BeginInvoke 之后随时可以调用该方法。 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成。 EndInvoke
的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。
(点此处获取更多介绍)
如果上面的介绍不明白,没有关系,下面我将通过一个简单的例子来进行演示。
先看一下程序主界面图,以便后面的代码说明较好理解:
从中可以看出,老黄可以同时烧开水和看电视,这就是异步。下面给出老黄类的定义:
我们在老黄类中声明了一个委托BoilWaterDelegate,并定义委托变量执行烧水的方法,利用BeginBoilWater和EndBoilWater来实现异步调用。在BeginBoilWater中有一个参数Action call,表示要接受一个没有参数返回值为void的委托。另外在调用BeginInvoke时,传入了回调函数CallBack,因此在执行烧开水的委托完成时将调用CallBack函数。可以看到,在CallBack函数中就用到了BeginInvoke中传入的参数call,因为它是一个委托,所以call()将执行它所定义的函数(此处为界面代码中的ActionCallBack)。
然后,给出界面中的代码:
由于ActionCallBack方法会在异步线程中执行,因此文本框需要利用Invoke方式来进行赋值。
于是就又再重新学习了一遍……
首先引用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(); } }
我们在老黄类中声明了一个委托BoilWaterDelegate,并定义委托变量执行烧水的方法,利用BeginBoilWater和EndBoilWater来实现异步调用。在BeginBoilWater中有一个参数Action call,表示要接受一个没有参数返回值为void的委托。另外在调用BeginInvoke时,传入了回调函数CallBack,因此在执行烧开水的委托完成时将调用CallBack函数。可以看到,在CallBack函数中就用到了BeginInvoke中传入的参数call,因为它是一个委托,所以call()将执行它所定义的函数(此处为界面代码中的ActionCallBack)。
然后,给出界面中的代码:
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()+"->"; }
由于ActionCallBack方法会在异步线程中执行,因此文本框需要利用Invoke方式来进行赋值。