C#异步工具类及一点小小的重构经验
2015年新年第一篇随笔,祝福虽然有些晚,但诚意还在:新年快乐。
今天主要是想分享一异步工具类,在C/S架构中、先进行网络资源异步访问,然后将回调函数Invoke到UI线程中进行UI处理。
这样的场景是及其常见的,因此特意封装了一工具类,用以简化操作。
///<summary>///异步工具类///</summary>publicclassTaskTools
{///<summary>///是否 在执行回调函数之前修改Running状态///</summary>publicboolChangeRunningStateBeforeCallback {get;PRivateset; }///<summary>///是否 正在执行异步任务///</summary>publicboolRunning {get;privateset; }publicTaskTools()
:this(false)
{
}///<summary>//////</summary>///<param name="changeRunningStateBeforeCallback">是否 在执行回调函数之前修改Running状态 默认值false</param>publicTaskTools(boolchangeRunningStateBeforeCallback)
{this.ChangeRunningStateBeforeCallback =changeRunningStateBeforeCallback;
}///<summary>///执行异步任务///</summary>///<typeparam name="T">异步任务返回值类型</typeparam>///<param name="control">操作UI时需要Invoke的控件</param>///<param name="asyncFunc">将要执行的任务任务</param>///<param name="callback">异步任务执行完毕后执行的回调函数</param>publicvoidRun<T>(Control control, Func<T> asyncFunc, Action<T>callback)
{if(this.Running)thrownewInvalidOperationException("the task is running");try{this.Running =true;
Task<T> task =newTask<T>(() =>{try{returnasyncFunc();
}catch(Exception ex)
{
Console.WriteLine(ex.Message);returndefault(T);
}
});
task.Start();
TaskContinue<T>(control, task, callback);
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
}finally{this.Running =false;
}
}///<summary>///执行异步任务///</summary>///<typeparam name="T">异步任务返回值类型</typeparam>///<param name="control">操作UI时需要Invoke的控件</param>///<param name="args">异步任务的传入参数</param>///<param name="asyncFunc">将要执行的任务任务</param>///<param name="callback">异步任务执行完毕后执行的回调函数</param>publicvoidRun<T>(Control control,objectargs, Func<object, T> asyncFunc, Action<T>callback)
{if(this.Running)thrownewInvalidOperationException("the task is running");try{this.Running =true;
Task<T> task =newTask<T>((lambdaObj) =>{try{returnasyncFunc(lambdaObj);
}catch(Exception ex)
{
Console.WriteLine(ex.Message);returndefault(T);
}
}, args);
task.Start();
TaskContinue<T>(control, task, callback);
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
}finally{this.Running =false;
}
}///<summary>///延时执行某任务///</summary>///<param name="control">操作UI时需要Invoke的控件</param>///<param name="milliSecond">将要延时执行的毫秒数</param>///<param name="callback">异步任务执行完毕后执行的回调函数</param>publicvoidDelayedRun(intmilliSecond, Control control, Action callback)
{this.Run<int>(control, () =>{
Thread.Sleep(milliSecond); // 4.0 类库returnmilliSecond;
}, (time)=>{
callback();
});
}///<summary>///Control.Invoke方法的简易封装///</summary>///<typeparam name="T">参数类型</typeparam>///<param name="control"></param>///<param name="args"></param>///<param name="action"></param>publicstaticvoidControlInvoke<T>(Control control, T args, Action<T>action)
{try{
Invoke<T>(control, args, action);
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}///<summary>///异步任务完成后继续执行...///</summary>///<typeparam name="T"></typeparam>///<param name="control"></param>///<param name="task"></param>///<param name="callback"></param>privatevoidTaskContinue<T>(Control control, Task<T> task, Action<T>callback)
{
task.ContinueWith((lambdaAction)=>{if(this.ChangeRunningStateBeforeCallback)
{this.Running =false;
}try{if(callback !=null)
{//有UI控件 则将回调函数注入到UI控件的相关线程中去执行if(control !=null)
{
TaskTools.Invoke<T>(control, lambdaAction.Result, callback);
}else{//否则在当前线程内执行 回调函数callback(lambdaAction.Result);
}
}
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
}finally{this.Running =false;
}
});
}///<summary>///Control.Invoke方法的简易封装///注意 无 Try Catch///</summary>///<typeparam name="T">参数类型</typeparam>///<param name="control"></param>///<param name="args"></param>///<param name="action"></param>privatestaticvoidInvoke<T>(Control control, T args, Action<T>action)
{//control为空,在当前线程内执行该actionif(control ==null)
{
action(args);return;
}//控件正在释放或者已经被释放则不执行actionif(control.Disposing ||control.IsDisposed)return;if(control.InvokeRequired)
{
control.Invoke(action,newobject[] { args });
}else{
action(args);
}
}
}
该工具类的使用,我想应该很简单吧。不过,我想借这个机会说一点小小的重构经验:委托类型(Action Func等等)的参数、尽量放在方法参数列表的最后边。
原因是:当直接使用Lambda表达式做参数时,格式化后的代码看起来更加优雅,更加易于阅读。例如:
重构前:
TaskTools task =newTaskTools(true);//延时 30 毫秒加载task.DelayedRun(() =>{//... 其他操作//延时 30 毫秒加载task.DelayedRun(() =>{//... 其他操作},30,this.pnlMainFill);
},30,this.pnlMainFill);
重构后:
TaskTools task =newTaskTools(true);//延时 30 毫秒加载task.DelayedRun(30,this.pnlMainFill, () =>{//... 其他操作//延时 30 毫秒加载task.DelayedRun(30,this.pnlMainFill, () =>{//... 其他操作});
});
VS重排参数列表快捷键: CTRL + R, O。