2015年新年第一篇随笔, 祝福虽然有些晚,但诚意还在:新年快乐。
今天主要是想分享一异步工具类,在C/S架构中、先进行网络资源异步访问,然后将回调函数 Invoke到UI线程中进行UI处理。
这样的场景是及其常见的,因此特意封装了一工具类,用以简化操作。
/// <summary> /// 异步工具类 /// </summary> public class TaskTools { /// <summary> /// 是否 在执行回调函数之前修改Running状态 /// </summary> public bool ChangeRunningStateBeforeCallback { get; PRivate set; } /// <summary> /// 是否 正在执行异步任务 /// </summary> public bool Running { get; private set; } public TaskTools() : this(false) { } /// <summary> /// /// </summary> /// <param name="changeRunningStateBeforeCallback">是否 在执行回调函数之前修改Running状态 默认值false</param> public TaskTools(bool changeRunningStateBeforeCallback) { this.ChangeRunningStateBeforeCallback = changeRunningStateBeforeCallback; } /// <summary> /// 执行异步任务 /// </summary> /// <typeparam name="T">异步任务返回值类型</typeparam> /// <param name="control">操作UI时需要Invoke的控件</param> /// <param name="asyncFunc">将要执行的任务任务</param> /// <param name="callback">异步任务执行完毕后执行的回调函数</param> public void Run<T>(Control control, Func<T> asyncFunc, Action<T> callback) { if (this.Running) throw new InvalidOperationException(" the task is running "); try { this.Running = true; Task<T> task = new Task<T>(() => { try { return asyncFunc(); } catch (Exception ex) { Console.WriteLine(ex.Message); return default(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> public void Run<T>(Control control, object args, Func<object, T> asyncFunc, Action<T> callback) { if (this.Running) throw new InvalidOperationException(" the task is running "); try { this.Running = true; Task<T> task = new Task<T>((lambdaObj) => { try { return asyncFunc(lambdaObj); } catch (Exception ex) { Console.WriteLine(ex.Message); return default(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> public void DelayedRun(int milliSecond, Control control, Action callback) { this.Run<int>(control, () => { Thread.Sleep(milliSecond); // 4.0 类库 return milliSecond; }, (time) => { callback(); }); } /// <summary> /// Control.Invoke方法的简易封装 /// </summary> /// <typeparam name="T">参数类型</typeparam> /// <param name="control"></param> /// <param name="args"></param> /// <param name="action"></param> public static void ControlInvoke<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> private void TaskContinue<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> private static void Invoke<T>(Control control, T args, Action<T> action) { // control为空,在当前线程内执行该action if (control == null) { action(args); return; } // 控件正在释放或者已经被释放则不执行action if (control.Disposing || control.IsDisposed) return; if (control.InvokeRequired) { control.Invoke(action, new object[] { args }); } else { action(args); } } }
该工具类的使用,我想应该很简单吧。不过,我想借这个机会说一点小小的重构经验:委托类型(Action Func等等)的参数、尽量放在方法参数列表的最后边。
原因是:当直接使用Lambda表达式做参数时,格式化后的代码看起来更加优雅,更加易于阅读。例如:
重构前:
TaskTools task = new TaskTools(true); // 延时 30 毫秒加载 task.DelayedRun(() => { // ... 其他操作 // 延时 30 毫秒加载 task.DelayedRun(() => { // ... 其他操作 }, 30, this.pnlMainFill); }, 30, this.pnlMainFill);
重构后:
TaskTools task = new TaskTools(true); // 延时 30 毫秒加载 task.DelayedRun(30, this.pnlMainFill, () => { //... 其他操作 // 延时 30 毫秒加载 task.DelayedRun(30, this.pnlMainFill, () => { //... 其他操作 }); });
VS重排参数列表快捷键: CTRL + R, O。
新闻热点
疑难解答