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

  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。

时间: 2024-11-06 17:03:47

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

异步工具类

public class TaskTools { /// <summary> /// 是否 在执行回调函数之前修改Running状态 /// </summary> public bool ChangeRunningStateBeforeCallback { get; private set; } /// <summary> /// 是否 正在执行异步任务 /// </summary> public bool Running { get; private se

Unity+NGUI打造网络图片异步加载与本地缓存工具类(一)

我们在移动端的开发中,异步网络图片加载用的非常的多,在unity当中虽然有AssetBundle的存在,一般是先加载好游戏资源然后再进入场景,但是还有不少地方能够用到异步网络图片的加载以及其缓存机制. 我之前也写过两个版本的ios中的异步网络图片加载helper类,所以今天按照同样的思路,也想做一个好用的helper类给大家使用以及简单的说下实现原理. 首先我们加载一张网络图片,要做的事情分步来讲为: 0.开始之前设置一张固定的图片作为占位图(placeholder),表示我们的图片还没加载好,

Android基础工具类重构系列一Toast

前言: 一直在考虑写一下Android实际项目中的一些总结,翻看CSDN博客,上一篇已经是一年多曾经. 本系列定位Android基础工具类重构.旨在记录实际项目中经经常使用到的一些工具类,比方Toast.Dialog.动画类,ImageLoader类等等.正在梳理,但发现梳理完再写预计黄花菜都凉了.所以改变策略,边写边梳理. 首先要写的就是这个Toast. 一.说明 作为Android系统提供的基类,Toast是最简单的提示消息类.特点悬浮.跨界面(Activity)特定时间内自己主动销毁. 二

和异步网络相关的工具类HttpUtils

和异步网络相关的工具类 package com.flyou.utils; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.HttpURLCon

【ListViewJson】【MainActivity功能性分析,不讨论具体工具类的实现】【android解析json数据(包含对图片数据的异步缓存处理),并将其加载到listview中】

最近遇到了一个相当好.对初学者相当友善的项目,是描述如何将json数据解析,并加载到listview中. 但是个人认为以后所有类似功能的实现都可以使用这套工具. 项目也可以使用这套架构. 这个项目是处理每个news只有一个imgurl,应该考虑一下当imgurl数量不定的时候具体应该怎么解决. 首先项目源码结构如下: 项目下载链接:http://download.csdn.net/download/y562810463/8004245 在这个项目中的com.demo.app.common包完全可

Unity+NGUI打造网络图片异步加载与本地缓存工具类(二)

接上文,我们的工具类中的主要方法: public  void SetAsyncImage(string url,UITexture texture) 按照前文分析的图片加载步骤来 public void SetAsyncImage(string url,UITexture texture){ //开始下载图片前,将UITexture的主图片设置为占位图 texture.mainTexture = placeholder; //判断是否是第一次加载这张图片 if (!File.Exists (pa

异步线程加载图片工具类

/** * 异步线程加载图片工具类 * 使用说明: * BitmapManager bmpManager; * bmpManager = new BitmapManager(BitmapFactory.decodeResource(context.getResources(), R.drawable.loading)); * bmpManager.loadBitmap(imageURL, imageView); */ public class BitmapManager { private st

Android消息机制——时钟显示和异步处理工具类(AsyncTask)

1. 时钟显示 定义布局文件——activity_my_analog_clock_thread_demo.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/to

重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)

一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用法及配置文件,这对于有些小工具.小程序.小网站来说,有点“杀鸡焉俺用牛刀”的感觉,而且如果对这些日志框架不了解,可能输出来的日志性能或效果未毕是与自己所想的,鉴于这几个原因,我自己重复造轮子,编写了一个轻量级的异步写日志的实用工具类(LogAsyncWriter),这个类还是比较简单的,实现思路也很