C#使用委托进行异步编程

最近项目中需要用到异步编程,虽然以前研究过,但时间一长竟然就都忘了尴尬于是就又再重新学习了一遍……

首先引用MSDN中的一段话来描述一下如何使用异步方式:

.NET Framework 允许您异步调用任何方法。 为此,应定义与您要调用的方法具有相同签名的委托;公共语言运行时会自动使用适当的签名为该委托定义 BeginInvoke 和 EndInvoke 方法。

BeginInvoke 方法启动异步调用。 该方法与您需要异步执行的方法具有相同的参数,还有另外两个可选参数。 第一个参数是一个AsyncCallback 委托,该委托引用在异步调用完成时要调用的方法。 第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。 BeginInvoke 立即返回,不等待异步调用完成。 BeginInvoke 返回一个IAsyncResult,后者可用于监视异步调用的进度。

EndInvoke 方法检索异步调用的结果。 在调用 BeginInvoke 之后随时可以调用该方法。 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成。 EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult。

(点此处获取更多介绍)

如果上面的介绍不明白,没有关系,下面我将通过一个简单的例子来进行演示。

先看一下程序主界面图,以便后面的代码说明较好理解:

C#使用委托进行异步编程_第1张图片

中可以看出,老黄可以同时烧开水和看电视,这就是异步。下面给出老黄类的定义:

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方式来进行赋值。




你可能感兴趣的:(C#使用委托进行异步编程)