zoukankan      html  css  js  c++  java
  • C# 异步工具类 及一点小小的重构经验

      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。

  • 相关阅读:
    C# tcp发送十六进制数据
    WPF中通过AForge实现USB摄像头拍照
    借鉴过的别人的帖子之C#篇
    C# 连续的语音识别
    C# NAudio 录音
    AS3 水波纹
    ARM多核心集群服务器
    RK3399Pro Android Rock-X 人工智能开发系列(2)
    智能化连锁门店解决方案
    RK3399Pro Android Rock-X 人工智能开发系列(1)
  • 原文地址:https://www.cnblogs.com/08shiyan/p/4226166.html
Copyright © 2011-2022 走看看