IT知识库 购物 网址 游戏 小说 歌词 快照 开发 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 编程 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> C# -> 自定义定时组件 -> 正文阅读

[C#]自定义定时组件

自定义定时组件   工作了这么久,封装过一部分Helper,也写过一些控件,但也没写过属于自己的框架,这次写的这个我觉得是一个组件而已,是一个定时组件。是一个定时器组件,有别于.NET Framework里面提供的几个Timer。首先说说背景,就发现现在手头上的工作离不开定时,定时做一个任务,什么都是定时去做什么什么,隔某段时间干某件事情,都离不开“定时”这个词。众所周知这个要用到多线程,在多篇关于多线程的文章里面有提过做一些周期性的操作时最好用Timer,当然这个Timer肯定是Threading.Timer,并不是WinForm控件里面的Timer。但我觉得在我的应用中Timer不够满足需求。
1.Timer只能在做任务与任务之间相隔一段时间的操作,如下图

但我需要的是这次任务开始的时刻到下次任务开始时刻是相隔同等的时间,又如下图

这样的情况下Timer则不能满足需求。
2.Timer的时间间隔一般是定的,但是如果要每次执行完任务要变动一下休眠的时间, 则需要调用Timer的Change方法。
3.Timer的休眠时间不是通过整形确定休眠的毫秒数,就是用一个TimeSpan来确定,对于那种到每天多少多少时刻或者到每小时的多少分执行一次的任务来说也不能够完全方便使用
对于上面这三种,鄙人对定时器封装了一下,弃用了Timer,还是用回了原有的Thread,定义了一种描述重复时间的模式字符串,计算出TimeSpan,从而调用Thread的Sleep()方法来休眠。下面展示整个组件的类图

最底下是两个关于时间计算方面的类,两个代理是两种任务方法的委托,基类BaseCycleMission是周期任务的积累,实现了ICycle接口,主要进行对任务线程的操控(开始,停止等),继承他的两个子类一个是实现上文第一点中我后来描述那种需求,一个类似于原有Timer的功能。它们各自使用不同的委托。MissionManager只是对所有周期任务的一个管理,统一去开启或暂停某一类的任务。
时间计算模块
  那首先来介绍一下定义的字符串模式。现在遇到的周期是有两种模式,
一种是每隔多长时间要执行一次的任务,这个是最普通的周期形式,以每个5分钟为例,完整的形式是“-99--99--99 -99:05:00”,“-99”是缺省的意思,当然还有其他简写的模式; 另一种是没到什么什么时候执行一次任务,例如没到中午12点为例完整的形式是“ff-ff-ff 12: ff:ff”,“ff”是默认的形式,当然也可以用“FF”,这里也有其他简写的模式。
所有字符串的模式如下表所示
 
每到***时刻
每隔***时间
完整
ffff-ff-ff ff:ff:ff 或
ff-ff-ff ff:ff:ff
-99--99--99 -99:-99:-99
日期部分
ffff-ff-ff 或
ff-ff-ff
-99--99--99
时间部分
ff:ff:ff 或
ff:ff:ff
-99:-99:-99
时间简写
ff:ff 或
ff:ff
-99:-99
  那么时间计算模块的处理流程是,给定了相应的模式字符串,TimePointConverter借助正则表达式匹配出对应的模式,返回匹配出来的年月日时分秒各个值,得出结果之后就调用SleepTimeProvider来计算出线程所要休眠的时间。下面则展示一下两个类的部分代码

 1     public class TimePointConverter
 2     {
 3         //其他成员
 4         private int[] DateTimeFixBuilder(string timeStr)
 5         {
 6             int[] result = null;
 7 
 8             string[] dtArray = timeStr.Split();
 9             string[] dateArray = dtArray[0].Split('-');
10             string[] timeArray = dtArray[1].Split(':');
11 
12             uint year,month,date;
13             uint hour, minute, second; 
14             uint.TryParse(dateArray[0], out year);
15             uint.TryParse(dateArray[1], out month);
16             uint.TryParse(dateArray[2], out date);
17 
18             uint.TryParse(timeArray[0], out hour);
19             uint.TryParse(timeArray[1], out minute);
20             uint.TryParse(timeArray[2], out second);
21 
22             //return InnerFixBuilder(year, month, date, hour, minute, second);
23             result = new int[] { (int)year, (int)month, (int)date, (int)hour, (int)minute, (int)second };
24             return result;
25         }
26         //其他成员
27     }


 1     public class SleepTimeProvider
 2 {
 3         //其他成员
 4         public TimeSpan InnerFixBuilder(uint year, uint month, uint date, uint hour, uint minute, uint second)
 5                 {
 6             uint[] uintTimeArray = new uint[6] { year, month, date, hour, minute, second };
 7             int[] intNowArray = new int[6] 
 8             {   
 9                 DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,
10                 DateTime.Now.Hour,DateTime.Now.Minute,DateTime.Now.Second 
11             };
12             int[] intTimeArray = new int[6];
13 
14             intTimeArray[0] = uintTimeArray[0] == 0 ? -DateTime.Now.Year : (int)uintTimeArray[0];
15             for (int i = 1; i < uintTimeArray.Length; i++)
16             {
17                 intTimeArray[i] = intTimeArray[i - 1] < 0 && uintTimeArray[i] == 0 ?
18                     -intNowArray[i] : (int)uintTimeArray[i];
19             }
20             DateTime goalTime = new DateTime(Math.Abs(intTimeArray[0]),
21                 Math.Abs(intTimeArray[1]),
22                 Math.Abs(intTimeArray[2]),
23                 Math.Abs(intTimeArray[3]),
24                 Math.Abs(intTimeArray[4]),
25                 Math.Abs(intTimeArray[5]));
26 
27 
28             if (goalTime < DateTime.Now)
29             {
30                 int max = -1;
31                 for (int i = intTimeArray.Length - 1; i >= 0; i--)
32                 {
33                     if (intTimeArray[i] < 0 && i > max)
34                     {
35                         max = i;
36                         intTimeArray[i]--;
37                     }
38                     intTimeArray[i] = Math.Abs(intTimeArray[i]);
39                 }
40                 goalTime = new DateTime(Math.Abs(intTimeArray[0]),
41                 Math.Abs(intTimeArray[1]),
42                 Math.Abs(intTimeArray[2]),
43                 Math.Abs(intTimeArray[3]),
44                 Math.Abs(intTimeArray[4]),
45                 Math.Abs(intTimeArray[5]));
46             }
47             return goalTime - DateTime.Now;
48         }
49 
50         //其他成员
51 }

线程调用模块
  线程调用模块是任务执行的核心部分,MissionEntiy是对线程操作的封装,主要负责开始,停止,暂停等操作。Thread用的是后台线程,对线程操作时也多做几个判断。例如暂停那个操作的定义如下

 1         public bool Pause()
 2         {
 3             if (actionThread == null) return false;
 4             if (actionThread.ThreadState == (System.Threading.ThreadState.Running | ThreadState.Background) ||
 5                 actionThread.ThreadState == (System.Threading.ThreadState.WaitSleepJoin | ThreadState.Background))
 6             {
 7                 actionThread.Suspend();
 8                 return true;
 9             }
10             return false;
11         }

  CycleMission是真正的任务载体,里面都同样有对线程的操作,但是又外加了一些时间处理,最核心的是让线程的BuildMainAction方法,这个方法是计算出要休眠的时间,让线程休眠,到点时调用适当的方法委托。

  1     public class BaseCycleMission:ICycleMission
  2     {
  3         //其他成员
  4 
  5         protected void BuildMainAction(string normalCycle, string overTimeCycle, object overTimeDelegate, bool isSleepBefore, bool isInclude)
  6         {
  7             mainAction = () =>
  8             {
  9                 TimeSpan sleepTime = TimeSpan.MinValue;
 10                 TimeSpan overTime = TimeSpan.MinValue;
 11                 bool result = true;
 12                 TimePointConvert.CircleType type;
 13 
 14                 #region 提前休眠
 15                 if (isSleepBefore)
 16                 {
 17                     type = TimePointConvert.Default.PraseType(normalCycle);
 18 
 19                     if (type == TimePointConvert.CircleType.Interval)
 20                         sleepTime = SleepTimeProvider.Defult.InnerIntervalBuilder(
 21                             TimePointConvert.Default.ConvertCircle(normalCycle));
 22                     else
 23                         sleepTime = SleepTimeProvider.Defult.InnerFixBuilder(
 24                         TimePointConvert.Default.ConvertCircle(normalCycle));
 25                     if (sleepTime.TotalMilliseconds > 0)
 26                         Thread.Sleep(sleepTime);
 27                 }
 28                 #endregion
 29 
 30                 while (true)
 31                 {
 32                     #region 计算时间
 33                     if (isInclude)
 34                     {
 35 
 36                         type = TimePointConvert.Default.PraseType(normalCycle);
 37 
 38                         sleepTime = type == TimePointConvert.CircleType.Interval ?
 39                             SleepTimeProvider.Defult.InnerIntervalBuilder(
 40                                 TimePointConvert.Default.ConvertCircle(normalCycle)) :
 41                             SleepTimeProvider.Defult.InnerFixBuilder(
 42                                 TimePointConvert.Default.ConvertCircle(normalCycle));
 43                         
 44 
 45                         type = TimePointConvert.Default.PraseType(overTimeCycle);
 46 
 47                         overTime = type == TimePointConvert.CircleType.Interval ?
 48                             SleepTimeProvider.Defult.InnerIntervalBuilder(
 49                                 TimePointConvert.Default.ConvertCircle(overTimeCycle)) :
 50                             SleepTimeProvider.Defult.InnerFixBuilder(
 51                                 TimePointConvert.Default.ConvertCircle(overTimeCycle));
 52 
 53                     }
 54                     #endregion
 55 
 56                     #region 执行方法
 57                     if (overTimeDelegate is OverTimeCycleDelegate)
 58                         result = (overTimeDelegate as OverTimeCycleDelegate).Invoke();
 59                     else
 60                     {
 61                         (overTimeDelegate as CycleDelegate).Invoke();
 62                         result = true;
 63                     }
 64                     #endregion
 65 
 66                     #region 计算时间
 67                     if (!isInclude)
 68                     {
 69 
 70 
 71                         type = TimePointConvert.Default.PraseType(normalCycle);
 72 
 73 
 74                         sleepTime = type == TimePointConvert.CircleType.Interval ?
 75                             SleepTimeProvider.Defult.InnerIntervalBuilder(
 76                                 TimePointConvert.Default.ConvertCircle(normalCycle)) :
 77                             SleepTimeProvider.Defult.InnerFixBuilder(
 78                                 TimePointConvert.Default.ConvertCircle(normalCycle));
 79 
 80                         type = TimePointConvert.Default.PraseType(overTimeCycle);
 81 
 82                         overTime = type == TimePointConvert.CircleType.Interval ?
 83                             SleepTimeProvider.Defult.InnerIntervalBuilder(
 84                                 TimePointConvert.Default.ConvertCircle(overTimeCycle)) :
 85                             SleepTimeProvider.Defult.InnerFixBuilder(
 86                                 TimePointConvert.Default.ConvertCircle(overTimeCycle));
 87                     }
 88                     #endregion
 89 
 90 
 91                     if (result)
 92                     {
 93                         if (sleepTime.TotalMilliseconds > 0)
 94                             Thread.Sleep(sleepTime);
 95                     }
 96                     else
 97                     {
 98                         if (overTime.TotalMilliseconds > 0)
 99                             Thread.Sleep(overTime);
100                     }
101                 }
102             };
103         }
104 
105         //其他成员
106     }

当然调用不是调用这个方法,调用只是调用它两个几类ExceptCycleMission和IncludeCycleMission,分别代表任务执行的时间不包括在周期里面和包括在周期里面两种。
管理器部分
  管理器主要是一个字典集,是一个ICycleMission和字符串的字典集,里面包含了对集合里面所有元素的操作:增加,删除,运行,恢复,暂停,停止。除了删除和增加,其他都包含了类似下面的方法

RunAllMission()
RunAllIncludeCycleMission()
RunAllExceptCycleMission()
RunMissionAmong(params string[] missionNames)
RunMissionExcept(params string[] missionNames)

但是这堆方法里面都调用了CallAction这个方法,

        private void CallAction(IEnumerable<ICycleMission> missionCollection,Action method)
        {
            if (missionCollection == null || method == null||missionCollection.Count()==0) return;
            
            foreach (ICycleMission item in missionCollection)
            {
                method.Method.Invoke(item, null);
            }
        }

例如在RunAllExceptCycleMission()方法里面调用如下

        public void RunAllExceptCycleMission()
        {
            CallAction(this.Values.Where(c => c is ExceptCycleMission), BaseCycleMission.Default.RunMission);
        }

  做这个组件应该是小题大做,毕竟看了那么久的《MVC框架揭秘》手痒,写了这个东西觉得框架里面的结构要设计好,命名也要命名好。
上一篇文章      下一篇文章      查看所有文章
加:2015-03-29 22:43:36  更:2017-05-14 17:14:37 
 
  C# 最新文章
字符串阵列分别输出元素的索引,原值和长度
格式化你的字符串
C#宣告一个变量
C#中级
拆分一个字符串并把每个字符单独输出
通过手机号定位归属地
C# DBNULL与NULL之间的区别【转】
Xamarin
List,DataTable实现行转列的通用方案
C# 语音识别
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 新闻资讯 小游戏 Chinese Culture 股票 三丰软件 开发 中国文化 网文精选 阅读网 看图 日历 万年历 2018年11日历
2018-11-14 0:46:10
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库