C# 异步工具类 及一点小小的重构经验

2018-06-17 20:02:23来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

  2015年新年第一篇随笔, 祝福虽然有些晚,但诚意还在:新年快乐。

  今天主要是想分享一异步工具类,在C/S架构中、先进行网络资源异步访问,然后将回调函数 InvokeUI线程中进行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。

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:.NET中的IO操作之文件流

下一篇:ADO.NET中带参数的Sql语句的陷阱