当前位置:  编程技术>.net/c#/asp.net

C#实现自定义定时组件的方法

    来源: 互联网  发布时间:2014-11-02

    本文导语:  本文实例展示的是一个自定义的定时器组件,有别于.NET Framework里面提供的几个Timer。首先说说该组件开发背景,发现现在手头上的工作离不开定时,定时做一个任务,什么都是定时去做什么什么,隔某段时间干某件事情,都离...

本文实例展示的是一个自定义的定时器组件,有别于.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来计算出线程所要休眠的时间。下面则展示一下两个类的部分代码

public class TimePointConverter
{
//其他成员
private int[] DateTimeFixBuilder(string timeStr)
{
int[] result = null;
string[] dtArray = timeStr.Split();
string[] dateArray = dtArray[0].Split('-');
string[] timeArray = dtArray[1].Split(':');

uint year,month,date;
uint hour, minute, second; 
uint.TryParse(dateArray[0], out year);
uint.TryParse(dateArray[1], out month);
uint.TryParse(dateArray[2], out date);

uint.TryParse(timeArray[0], out hour);
uint.TryParse(timeArray[1], out minute);
uint.TryParse(timeArray[2], out second);

//return InnerFixBuilder(year, month, date, hour, minute, second);
result = new int[] { (int)year, (int)month, (int)date, (int)hour, (int)minute, (int)second };
return result;
}
//其他成员
}
public class SleepTimeProvider
{
//其他成员
public TimeSpan InnerFixBuilder(uint year, uint month, uint date, uint hour, uint minute, uint second)
{
uint[] uintTimeArray = new uint[6] { year, month, date, hour, minute, second };
int[] intNowArray = new int[6] 
{ 
DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,
DateTime.Now.Hour,DateTime.Now.Minute,DateTime.Now.Second 
};
int[] intTimeArray = new int[6];
intTimeArray[0] = uintTimeArray[0] == 0 ? -DateTime.Now.Year : (int)uintTimeArray[0];
for (int i = 1; i < uintTimeArray.Length; i++)
{
intTimeArray[i] = intTimeArray[i - 1] < 0 && uintTimeArray[i] == 0 ?
-intNowArray[i] : (int)uintTimeArray[i];
}
DateTime goalTime = new DateTime(Math.Abs(intTimeArray[0]),
Math.Abs(intTimeArray[1]),
Math.Abs(intTimeArray[2]),
Math.Abs(intTimeArray[3]),
Math.Abs(intTimeArray[4]),
Math.Abs(intTimeArray[5]));
if (goalTime < DateTime.Now)
{
int max = -1;
for (int i = intTimeArray.Length - 1; i >= 0; i--)
{
if (intTimeArray[i] < 0 && i > max)
{
max = i;
intTimeArray[i]--;
}
intTimeArray[i] = Math.Abs(intTimeArray[i]);
}
goalTime = new DateTime(Math.Abs(intTimeArray[0]),
Math.Abs(intTimeArray[1]),
Math.Abs(intTimeArray[2]),
Math.Abs(intTimeArray[3]),
Math.Abs(intTimeArray[4]),
Math.Abs(intTimeArray[5]));
}
return goalTime - DateTime.Now;
}
//其他成员
}

线程调用模块

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

public bool Pause()
{
if (actionThread == null) return false;
if (actionThread.ThreadState == (System.Threading.ThreadState.Running | ThreadState.Background) ||
actionThread.ThreadState == (System.Threading.ThreadState.WaitSleepJoin | ThreadState.Background))
{
actionThread.Suspend();
return true;
}
return false;
}

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

public class BaseCycleMission:ICycleMission
{
//其他成员
protected void BuildMainAction(string normalCycle, string overTimeCycle, object overTimeDelegate, bool isSleepBefore,bool isInclude)
{
mainAction = () =>
{
TimeSpan sleepTime=TimeSpan.MinValue;
bool result = true;
TimePointConvert.CircleType type ;
#region 提前休眠
if (isSleepBefore)
{
type = TimePointConvert.Default.PraseType(normalCycle); 
if (type == TimePointConvert.CircleType.Interval)
sleepTime = SleepTimeProvider.Defult.InnerIntervalBuilder(
TimePointConvert.Default.ConvertCircle(normalCycle));
else
sleepTime = SleepTimeProvider.Defult.InnerFixBuilder(
TimePointConvert.Default.ConvertCircle(normalCycle));
if (sleepTime.TotalMilliseconds > 0)
Thread.Sleep(sleepTime);
}
#endregion
while (true)
{
#region 计算时间
if (isInclude)
{
if (result)
{
type = TimePointConvert.Default.PraseType(normalCycle); 
type = TimePointConvert.Default.PraseType(overTimeCycle); 
sleepTime = type == TimePointConvert.CircleType.Interval ?
SleepTimeProvider.Defult.InnerIntervalBuilder(
TimePointConvert.Default.ConvertCircle(overTimeCycle)) :
SleepTimeProvider.Defult.InnerFixBuilder(
TimePointConvert.Default.ConvertCircle(overTimeCycle));
}
}
#endregion

#region 执行方法

if(overTimeDelegate is OverTimeCycleDelegate)
result = (overTimeDelegate as OverTimeCycleDelegate).Invoke();
else
{
(overTimeDelegate as CycleDelegate).Invoke();
result = true;
}
#endregion

#region 计算时间
if (!isInclude)
{
if (result)
{

type = TimePointConvert.Default.PraseType(normalCycle);


sleepTime = type == TimePointConvert.CircleType.Interval ?
SleepTimeProvider.Defult.InnerIntervalBuilder(
TimePointConvert.Default.ConvertCircle(normalCycle)) :
SleepTimeProvider.Defult.InnerFixBuilder(
TimePointConvert.Default.ConvertCircle(normalCycle));
}
else
{
type = TimePointConvert.Default.PraseType(overTimeCycle);

sleepTime = type == TimePointConvert.CircleType.Interval ?
SleepTimeProvider.Defult.InnerIntervalBuilder(
TimePointConvert.Default.ConvertCircle(overTimeCycle)) :
SleepTimeProvider.Defult.InnerFixBuilder(
TimePointConvert.Default.ConvertCircle(overTimeCycle));
}
}
#endregion

if (sleepTime.TotalMilliseconds > 0)
Thread.Sleep(sleepTime);
}
};
}
//其他成员
}

当然调用不是调用这个方法,调用只是调用它两个几类ExceptCycleMission和IncludeCycleMission,分别代表任务执行的时间不包括在周期里面和包括在周期里面两种。

管理器部分

  管理器主要是一个字典集,是一个ICycleMission和字符串的字典集,里面包含了对集合里面所有元素的操作:增加,删除,运行,恢复,暂停,停止。除了删除和增加,其他都包含了类似下面的方法

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

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

private void CallAction(IEnumerable 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);
}

  感兴趣的朋友可以测试一下本文所述实例代码,相信会有不小的收获!


    
 
 

您可能感兴趣的文章:

  • c#通过委托delegate与Dictionary实现action选择器代码举例
  • C#实现获取枚举中元素个数的方法
  • C#实现自定义双击事件
  • C#键盘输入回车键实现点击按钮效果的方法
  • C#实现获取一年中是第几个星期的方法
  • C#实现Datatable排序的方法
  • C#实现装箱与拆箱操作简单实例
  • 解决C#中WebBrowser的DocumentCompleted事件不执行的实现方法
  • C#下实现创建和删除目录的实例代码
  • 使用C#实现在屏幕上画图效果的代码实例
  • C#实现过滤html标签并保留a标签的方法
  • c#实现TextBox只允许输入数字
  • C# Winform 整个窗口拖动的实现代码
  • c# ListView实现双击Item事件的变通方法
  • C#实现随鼠标移动窗体实例
  • C#中的FileUpload 选择后的预览效果具体实现
  • C# 窗体隐藏及任务管理器中禁止关闭的实现代码
  • C#的锯齿数组以及C++实现代码
  • C#格式化文件大小的实现代码
  • C#怎样才能实现窗体最小化到托盘呢?
  • C# char类型字符转换大小写的实现代码
  • 在java的GUI的应用程序中能否实现对容器(如Frame)中的所有组件遍历?
  • 使用#default#userdata组件实现的可记忆内容的编辑器
  • C# 无需COM组件创建快捷方式的实现代码
  • 利用微软com组件mstscax.dll实现window7远程桌面功能
  • 请问java的GUI界面如何实现缩放窗口时组件不跟着变形,100分发上兑现
  • Java实现鼠标拖拽移动界面组件
  • Android实现动态切换组件背景的方法
  • Oracle组件实现动态Web数据库
  • android Gallery组件实现的iPhone图片滑动效果实例
  • 如何实现表格在同一个 column 的不同 cell 放进不同种类的组件,各大侠提点一下!---我只有41分啦
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • c++通用模板类(template class)定义实现详细介绍
  • linux怎样实现自定义指令"cd -n"
  • 我想定义一个宏来实现文中功能,但是不知道我说的功能到底可不可以实现
  • 菜鸟提问:一个类实现了一个接口,除了要定义接口的所有方法外,可不可以再添加其他方法?
  • 自定义标签实现圆角边框
  • 如何实现C#自定义结构的强制转换
  • jQuery自定义事件的简单实现代码
  • C#自定义控件添加右键菜单的实现代码
  • 如何跟踪进入C++定义实现的文件中?
  • java 重定义数组的实现方法(与VB的ReDim相像)
  • C#使用yield关键字让自定义集合实现foreach遍历的方法
  • php实现的太平洋时间和北京时间互转的自定义函数分享
  • C# Form自定义光标的简单实现
  • php自定义函数实现美国时间转为北京时间
  • 在JAVA中的抽象类中有必要定义抽象方法吗?我直接在它的子类中定义并实现这个方法不一样吗?
  • Visual C#类的定义及实现方法实例解析
  • Python def函数的定义、使用及参数传递实现代码
  • PHP采用自定义函数实现遍历目录下所有文件的方法
  • DevExpress实现自定义TreeListNode的Tooltip的方法
  • sql server实现的自定义Split函数
  • C# .NET自定义类实现伪静态页面的代码
  • 通过javascript实现DIV居中,兼容各浏览器版本
  • socket实现多文件并发传输,求助多线程实现问题?
  • Python GUI编程:tkinter实现一个窗口并居中代码
  • interface 到底有什么用???实现接口,怎么实现??
  • 通过javascript库JQuery实现页面跳转功能代码
  • 怎么用Jsp实现在页面实现树型结构?
  • sharepoint 2010 使用STSNavigate函数实现文件下载举例
  • windows 下的PortTunnel 在linux下怎么实现?或者相应的已经实现的软件?端口映射
  • php实现socket实现客户端和服务端数据通信源代码
  • 网站重定向用C语言实现iptables,ACL实现


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3