当UI动作引发一个耗时的计算时,我们经常需要将这个耗时的过程放到后台线程中去完成,然后获取该过程的结果。使用.NET提供的默认设施,无论是使用Thread还是使用异步调用,细节都比较繁琐。在前几天的blog上也看到了有些兄台的解决方案,但是觉得还不够好用,于是自己封了一个AsynCaller。
AsynCaller通过事件来通知外部异步调用的结果,IAsynCaller接口如下:
publicinterfaceIAsynCaller
{
//Delegate用于动态调用目标方法
voidInitialize(Delegatemethod,object[]args);
voidStart();//启动异步操作
voidCancel();//取消操作
eventCBackTaskCompletedTaskCompleted;
eventCBackExceptionThrownExceptionThrown;
eventCBackTaskCanceledTaskCanceled;
}
publicdelegatevoidCBackTaskCompleted(objectresult);
publicdelegatevoidCBackExceptionThrown(Exceptionee);
publicdelegatevoidCBackTaskCanceled();
{
//Delegate用于动态调用目标方法
voidInitialize(Delegatemethod,object[]args);
voidStart();//启动异步操作
voidCancel();//取消操作
eventCBackTaskCompletedTaskCompleted;
eventCBackExceptionThrownExceptionThrown;
eventCBackTaskCanceledTaskCanceled;
}
publicdelegatevoidCBackTaskCompleted(objectresult);
publicdelegatevoidCBackExceptionThrown(Exceptionee);
publicdelegatevoidCBackTaskCanceled();
上面的接口清晰易懂,所需要注意的就是Initialize方法,它的第一个参数是需要进行异步调用的目标方法的委托,Delegate就像一个万能的delegate,它可以匹配到任何签名的方法。
接口出来后,其实现AsynCaller就很容易写了。
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->publicclassAsynCaller:IAsynCaller
{
privateDelegatetarget=null;
privateobject[]theArgs=null;
privateThreadbackThread=null;
privateboolcanceled=false;
privateCBackTaskCompletedtaskCompleted;
privateCBackExceptionThrownexceptionThrown;
privateCBackTaskCanceledtaskCanceled;
#regionIAsynCaller成员
publicvoidInitialize(Delegatemethod,object[]args)
{
this.target=method;
this.theArgs=args;
}
publicvoidStart()
{
this.backThread=newThread(newThreadStart(this.BackThread));
this.backThread.Start();
}
publicvoidCancel()
{
this.canceled=true;
this.backThread.Abort();
}
#regionBackThread
privatevoidBackThread()
{
try
{
objectresult=this.target.DynamicInvoke(this.theArgs);//动态调用
this.ActivateTaskCompleted(result);
}
catch(Exceptionee)
{
if((this.canceled)||(eeisThreadAbortException))//任务被取消
{
this.ActivateTaskCanceled();
}
else
{
this.ActivateExceptionThrown(ee);
}
}
}
#endregion
#regionevent
privatevoidActivateTaskCompleted(objectresult)
{
if(this.taskCompleted!=null)
{
this.taskCompleted(result);
}
}
privatevoidActivateExceptionThrown(Exceptionee)
{
if(this.exceptionThrown!=null)
{
this.exceptionThrown(ee);
}
}
privatevoidActivateTaskCanceled()
{
if(this.taskCanceled!=null)
{
this.taskCanceled();
}
}
publiceventCBackTaskCompletedTaskCompleted
{
add
{
this.taskCompleted+=value;
}
remove
{
this.taskCompleted-=value;
}
}
publiceventCBackTaskCanceledTaskCanceled
{
add
{
this.taskCanceled+=value;
}
remove
{
this.taskCanceled-=value;
}
}
publiceventCBackExceptionThrownExceptionThrown
{
add
{
this.exceptionThrown+=value;
}
remove
{
this.exceptionThrown-=value;
}
}
#endregion
#endregion
}
下面给出一个示例来说明如何使用IAsynCaller。
比如在一个Form中,有两个按钮,一个用于启动异步调用,一个用于取消操作。首先写一个耗时的方法,用于异步调用:
privatevoidComputeTask(intcount)
{
for(inti=0;i<count;i++)
{
Thread.Sleep(500);
this.label1.Text=string.Format("第{0}次",i);
}
}
然后在Form中添加成员变量:{
for(inti=0;i<count;i++)
{
Thread.Sleep(500);
this.label1.Text=string.Format("第{0}次",i);
}
}
privateIAsynCallertheAsynCaller=null;
在构造函数中,初始化theAsynCaller,并预定对应的事件:
object[]args={30};
this.theAsynCaller=newAsynCaller();
this.theAsynCaller.Initialize(newCBack1(this.ComputeTask),args);
this.theAsynCaller.TaskCanceled+=newCBackTaskCanceled(theAsynCaller_TaskCanceled);
this.theAsynCaller.TaskCompleted+=newCBackTaskCompleted(theAsynCaller_TaskCompleted);
事件处理函数如下:this.theAsynCaller=newAsynCaller();
this.theAsynCaller.Initialize(newCBack1(this.ComputeTask),args);
this.theAsynCaller.TaskCanceled+=newCBackTaskCanceled(theAsynCaller_TaskCanceled);
this.theAsynCaller.TaskCompleted+=newCBackTaskCompleted(theAsynCaller_TaskCompleted);
privatevoidbutton1_Click(objectsender,System.EventArgse)
{
this.theAsynCaller.Start();
}
privatevoidbutton2_Click(objectsender,System.EventArgse)
{
this.theAsynCaller.Cancel();
}
privatevoidtheAsynCaller_TaskCanceled()
{
MessageBox.Show("TaskCanceled");
}
privatevoidtheAsynCaller_TaskCompleted(objectresult)
{
MessageBox.Show("Taskcomplete");
}
{
this.theAsynCaller.Start();
}
privatevoidbutton2_Click(objectsender,System.EventArgse)
{
this.theAsynCaller.Cancel();
}
privatevoidtheAsynCaller_TaskCanceled()
{
MessageBox.Show("TaskCanceled");
}
privatevoidtheAsynCaller_TaskCompleted(objectresult)
{
MessageBox.Show("Taskcomplete");
}
为了简化,上面的示例在后台线程中调用的了UI显示,这在真正的应用中是万万不可的。同时要注意,上面的示例中,IAsynCaller接口事件的事件处理函数也是在后台线程中调用的,也存在同样的问题。
当UI动作引发耗时计算时,需将其放至后台线程并获取结果。使用.NET默认设施处理细节繁琐,已有解决方案不够好用,因此作者封装了AsynCaller,它通过事件通知外部异步调用结果。
529

被折叠的 条评论
为什么被折叠?



