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(() =>
{
// ... 其他操作
}, , this.pnlMainFill);
}, , this.pnlMainFill);
重构后:
TaskTools task = new TaskTools(true);
// 延时 30 毫秒加载
task.DelayedRun(, this.pnlMainFill, () =>
{
//... 其他操作
// 延时 30 毫秒加载
task.DelayedRun(, this.pnlMainFill, () =>
{
//... 其他操作
});
});
VS重排参数列表快捷键: CTRL + R, O。
C# 异步工具类 及一点小小的重构经验的更多相关文章
- C#操作Control异步工具类
/// <summary> /// 异步工具类 /// </summary> public class TaskTools { /// <summary> /// ...
- Hibernate.基础篇《一》.Hibernate工具类.
Hibernate.基础篇<一>.Hibernate工具类. 话述: Hibernate.基础篇第一篇,前面是代码.后面再加理论&实践. Hibernate使用的版本是:5.x,在 ...
- Android消息机制——时钟显示和异步处理工具类(AsyncTask)
1. 时钟显示 定义布局文件——activity_my_analog_clock_thread_demo.xml <?xml version="1.0" encoding=& ...
- 重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)
一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用 ...
- c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习
c#中@标志的作用 参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...
- JDBC实例--工具类升级,使用Apache DBCP连接池重构DBUtility,让连接数据库更有效,更安全
直接使用JDBC访问数据库时,需要避免以下隐患: 1. 每一次数据操作请求都需要建立数据库连接.打开连接.存取数据和关闭连接等步骤.而建立和打开数据库连接是一件既耗资源又费时的过程,如果频繁发生这种数 ...
- Android基础工具类重构系列一Toast
前言: 一直在考虑写一下Android实际项目中的一些总结,翻看CSDN博客,上一篇已经是一年多曾经. 本系列定位Android基础工具类重构.旨在记录实际项目中经经常使用到的一些工具类,比方Toas ...
- 从接口自动化测试框架设计到开发(二)操作json文件、重构json工具类
用例模板里的请求数据多,看起来很乱,所以可以通过访问另外一个文件的方式获取请求数据 把请求数据都放在一个json文件中 取出login的内容: import json fp = open('G:/un ...
- Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
Go/Python/Erlang编程语言对比分析及示例 本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...
随机推荐
- DOM何时Ready
由于script标签在被加载完成后会立即执行其中代码,如果在代码中要访问HTMLElement,可是这时候元素还没有加载进来,所以对元素的操作统统无效. 最早的时候使用window.onload = ...
- 【读书笔记】Programming Entity Framework CodeFirst -- 初步认识
以下是书<Programming Entity Framework Code First>的学习整理,主要是一个整体梳理. 一.模型属性映射约定 1.通过 System.Component ...
- Guava - EventBus(事件总线)
Guava在guava-libraries中为我们提供了事件总线EventBus库,它是事件发布订阅模式的实现,让我们能在领域驱动设计(DDD)中以事件的弱引用本质对我们的模块和领域边界很好的解耦设计 ...
- leveldb源码学习系列
楼主从2014年7月份开始学习<>,由于书籍比较抽象,为了加深思考,同时开始了Google leveldb的源码学习,主要是想学习leveldb的设计思想和Google的C++编程规范.目 ...
- 优雅的使用python之环境管理
优雅的使用python之环境管理 缘起 情景1:不同python版本的管理 同一电脑上的多个python版本之前的管理,为了突出问题的普遍存在,下面是有人在segmentfault上提的问题. 摘自: ...
- java.sql.SQLException: No suitable driver 问题解决
最近在学习java,用到c3p0数据库连接池,遇到一个很奇怪的现象,用main方法测试是可以正常连接数据库的,但是使用jsp调用代码,就会报如下图的错误! 最下面的java.sql.SQLExcept ...
- 科蓝软件急招前端开发、PHP、.NET工程师
职位:前端开发 工作年限:不限 学历要求:大专 招聘人数:2 专业:不限 薪酬:面议 工作地点:浙江嘉兴.北京 岗位职责: 1.负责公司项目的UI设计: 2.负责将UI静态化 ...
- JavaScript包装对象
JavaScript是面向对象的语言,使用”.”操作符可以访问对象的属性和方法,而对于基本类型(null, undefined, bool, number, string)应该是值类型,没有属性和方法 ...
- Windows Live Writer 初次使用
Windows Live Writer 博客园文章的一款发布器,这篇文章就是通过其发布的,可以先在word中写好博客内容,直接粘贴到这里发布就OK,之前我都是先在Word中写好一份,然后在blogs ...
- Spring Trasnaction管理(3)- 事务嵌套
问题导读 Spring 如何管理嵌套的事务 Spring事务传播机制 Nested 和 RequireNew 有何区别 事务传播机制 事务的传播机制应该都比较熟悉 在日常开发中会遇到需要事务嵌套的情况 ...