您的位置:首页 > 编程语言 > C#

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。

(点此处获取更多介绍)

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

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



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

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方式来进行赋值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: