C#開發系統服務時用的定時器組件,
[csharp] view plaincopy
- // 相較上一版本改進
- // 1. 修改Bug
- // 當設置每月一次頻率時,設置的Day日期如果為31,30,29,在有些年份的有些月份會拋出異常,因為有些月份是沒有31天的,改正之後,
- // 如果設置了31天,則只有有31天的月份會執行。
- // 2. 修正一年中某天的日期較驗功能。
- // 3. 新增加循環模式
- // 每個月最後一天執行一次。
- // 4. 支持到秒的定時
[csharp] view plaincopy
- using System;
- using System.Text;
- using System.Windows.Forms;
- using UpSoft.Framework.CommonFunction.WinService;
-
- namespace TestProject
- {
- /// <summary>
- /// 測試服務
- /// </summary>
- public class TestServices : ServiceTimerControl
- {
- /// <summary>
- /// 服務代碼
- /// </summary>
- protected override void StartService()
- {
- // 需要處理的服務代碼
- }
-
- /// <summary>
- /// 時間配置策略名(可不重寫。默認讀配置文件中的default)
- /// </summary>
- public override string ConfigName { get { return "A"; } }
- }
- }
-
-
- 要調用時,只需輸入以下代碼
- new TestServices().Start();
[csharp] view plaincopy
- //時間策略配置,可選擇以下兩種之一,配置文件,或是重寫實現基類的獲取時間策略配置
- //1.代碼重寫
- /// <summary>
- /// 時間策略配置
- /// </summary>
- /// <returns></returns>
- protected override TimerConfig GetTimerConfig()
- {
- return new TimerConfig{ TimerMode=..., ...};
- }
- //2.配置文件實現
[html] view plaincopy
- <?xml version="1.0" encoding="utf-8"?>
- <configuration>
- <configSections>
- <section name="ServiceTimerConfig" type="UpSoft.Framework.CommonFunction.WinService.ServiceTimerConfigManager,CommonFunction"></section>
- </configSections>
- <ServiceTimerConfig>
- <!--默認采用策略-->
- <Default>A</Default>
- <!--A配置項(全節點)-->
- <Config>
- <!--A策略-->
- <RefName>A</RefName>
- <TimerMode>Interval</TimerMode>
- <!--延遲開始處理(單位毫秒)可為空-->
- <Delay>10000</Delay>
- <!--文件生成時間間隔(單位毫秒,1800000=30分鐘)-->
- <Interval>600000</Interval>
- <!--月份-->
- <MonthSeq></MonthSeq>
- <!--指定第幾天的序號-->
- <DaySeq></DaySeq>
- <!--定時配置-->
- <Times>
- <!--一天之中需要執行任務的時間點-->
- <TimeValue>11:20:19</TimeValue>
- <TimeValue>10:10:43</TimeValue>
- <TimeValue>19:10:28</TimeValue>
- </Times>
- </Config>
- <!--B配置項(輪詢策略)-->
- <Config>
- <!--B策略,每隔設置的時間執行一次-->
- <RefName>B</RefName>
- <TimerMode>Interval</TimerMode>
- <!--延遲開始處理(單位毫秒)-->
- <Delay>10000</Delay>
- <!--文件生成時間間隔(單位毫秒,1800000=30分鐘)-->
- <Interval>600000</Interval>
- </Config>
- <!--C配置項(天設置)-->
- <Config>
- <!--C策略,每周4在配置的時間點上執行-->
- <RefName>C</RefName>
- <TimerMode>Week</TimerMode>
- <!--延遲開始處理(單位毫秒)-->
- <Delay>10000</Delay>
- <!--每周的星期四的以下時間執行-->
- <DaySeq>4</DaySeq>
- <!--定時配置-->
- <Times>
- <!--一天之中需要執行任務的時間點-->
- <TimeValue>11:20:19</TimeValue>
- <TimeValue>10:10:43</TimeValue>
- <TimeValue>19:10:28</TimeValue>
- </Times>
- </Config>
- <!--D配置項(月、天設置)-->
- <Config>
- <!--D策略,每年12月8號在配置的時間點上執行-->
- <RefName>D</RefName>
- <TimerMode>Month</TimerMode>
- <!--延遲開始處理(單位毫秒)-->
- <Delay>10000</Delay>
- <!--月份-->
- <MonthSeq>12</MonthSeq>
- <!--天數-->
- <DaySeq>8</DaySeq>
- <!--定時配置-->
- <Times>
- <!--一天之中需要執行任務的時間點-->
- <TimeValue>11:20:19</TimeValue>
- <TimeValue>10:10:43</TimeValue>
- <TimeValue>19:10:28</TimeValue>
- </Times>
- </Config>
- </ServiceTimerConfig>
- </configuration>
-
- // TimerMode的定義
- public enum TimerMode
- {
- ///<summary>
- /// 輪詢方式
- /// </summary>
- Interval = 0,
- /// <summary>
- /// 一個月中某個天數的指定時間
- /// </summary>
- Month = 1,
- /// <summary>
- /// 一周中的周幾的指定時間
- /// </summary>
- Week = 2,
- /// <summary>
- /// 一天中的指定時間
- /// </summary>
- Day = 3,
- /// <summary>
- /// 一年中第幾天的指定時間
- /// </summary>
- Year = 4,
- /// <summary>
- /// 一年中的指定日期的指定時間
- /// </summary>
- Date = 5,
- /// <summary>
- /// 每個月倒數第N天
- /// </summary>
- LastDayOfMonth
- /// <summary>
- /// 未設置
- /// </summary>
- NoSet
- }
以下是組件的源代碼
[csharp] view plaincopy
- using System;
- using System.Collections.Generic;
- using System.Configuration;
- using System.Text.RegularExpressions;
- using System.Threading;
- using System.Xml;
-
- namespace UpSoft.Framework.CommonFunction.WinService
- {
- /// <summary>
- /// 服務定時器管理
- /// </summary>
- public abstract class ServiceTimerControl
- {
- #region 私有成員
- /// <summary>
- /// 定時器
- /// </summary>
- private Timer SysTimer { get; set; }
- /// <summary>
- /// 是否啟用定時器
- /// </summary>
- private bool _EnabledTimer = true;
- /// <summary>
- /// 服務執行狀態, 0-休眠, 1-運行
- /// </summary>
- private int _serviceStatus = 0;
- #endregion
-
- #region 公共屬性
- /// <summary>
- /// 獲取服務狀態
- /// </summary>
- public int ServiceStatus { get { return _serviceStatus; } }
-
- /// <summary>
- /// 定時器配置
- /// </summary>
- public TimerConfig Config { get; set; }
-
- /// <summary>
- /// 時間計算類
- /// </summary>
- public TimerControl TimerControl { get; set; }
-
- /// <summary>
- /// 配置名稱
- /// </summary>
- public virtual string ConfigName { get { return ( ServiceTimerConfigManager.ServiceConfig == null ? "" : ServiceTimerConfigManager.ServiceConfig.Default ); } }
- #endregion
-
- /// <summary>
- /// 停止
- /// </summary>
- public void Stop()
- {
- _EnabledTimer = false;
-
- if ( SysTimer != null ) SysTimer.Change( Timeout.Infinite, Timeout.Infinite );
- }
-
- /// <summary>
- /// 開始服務
- /// </summary>
- public void Start()
- {
- try
- {
- _EnabledTimer = true;
- Config = this.GetTimerConfig();
- if ( Config.Delay == null )
- Config.Delay = new TimeSpan( 0 );
-
- SysTimer = new Timer( new TimerCallback( this.TimerProcess ), AppDomain.CurrentDomain, Config.Delay, this.Config.Interval );
-
- this.Logger( LogLevel.INFO, "服務啟動成功!" );
- }
- catch ( Exception ex )
- {
- this.ServiceException( ex );
- }
- }
-
- /// <summary>
- /// 單次執行服務程序
- /// </summary>
- public void Process()
- {
- try
- {
- //開始處理服務
- this.StartService();
- }
- catch ( Exception ex ) { this.ServiceException( ex ); } // 處理服務執行過程中出現的異常
- }
-
- /// <summary>
- /// 處理間隔服務
- /// </summary>
- /// <param name="sender"></param>
- private void TimerProcess( object sender )
- {
- if ( !_EnabledTimer ) return;
-
- bool TimeIsUp = true;
- if ( this.Config.TimerMode != TimerMode.Interval )
- {
- // 如果定時方式不是定時輪詢的話,就構造TimerControl類,該類用來計算每次執行完程序後
- // 到下次執行服務時需要休眠的時間
- try
- {
- this.TimerControl = new TimerControl( this.Config );
- TimeIsUp = this.TimerControl.TimeIsUp; // 獲取是否到了執行服務程序的時間了
- }
- catch ( Exception ex )
- {
- // 讀取配置出錯且TimerControl對象已不存在,則再拋出異常
- // 如果上一次讀取配置成功,那就就算這次的配置有問題,則也不會停止程序的運行,仍用上一次的數據做為參數
- if ( this.TimerControl == null ) throw ex;
- }
- }
-
- try
- {
- if ( TimeIsUp )// 時間到了可以執行程序了
- {
- // 服務運行了
- _serviceStatus = 1;
-
- // 設置計時器,在無窮時間後再啟用(實際上就是永遠不啟動計時器了--停止計時器計時)
- SysTimer.Change( Timeout.Infinite, Timeout.Infinite );
-
- //開始處理服務
- this.StartService();
- }
- }
- catch ( Exception ex ) { this.ServiceException( ex ); } // 處理服務執行過程中出現的異常
- finally
- {
- // 如果計時器不為空,則重新設置休眠的時間
- if ( SysTimer != null )
- {
- if ( this.Config.TimerMode == TimerMode.Interval )// 定時輪詢設置
- {
- // 重新啟用計時器
- SysTimer.Change( this.Config.Interval, this.Config.Interval );
- }
- else// 定時設置
- {
- // 用cft類計算下一次到期的時間
- TimeSpan Interval = this.TimerControl.GetNextTimeUp();
- // 重新啟用計時器
- SysTimer.Change( Interval, Interval );
- }
- }
- _serviceStatus = 0;
- }
- }
-
- /// <summary>
- /// 開始服務
- /// </summary>
- protected abstract void StartService();
-
- /// <summary>
- /// 記錄日志
- /// </summary>
- /// <param name="level">錯誤級別</param>
- /// <param name="msg"></param>
- protected virtual void Logger( LogLevel level, string msg ) { return; }
-
- /// <summary>
- /// 定時器初始化
- /// </summary>
- protected virtual TimerConfig GetTimerConfig()
- {
- var config = ServiceTimerConfigManager.ServiceConfig;
- if ( config != null && config.Config.Length > 0 )
- {
- // 如果沒有配置則默認為第1個
- if ( String.IsNullOrEmpty( ConfigName ) )
- return config.Config[0];
- else// 返回配置項
- foreach ( var c in config.Config ) if ( String.Compare( c.RefName, ConfigName, true ) == 0 ) return c;
- }
-
- throw new Exception( "時間策略配置不正確!" );
- }
-
- /// <summary>
- /// 系統服務錯誤
- /// </summary>
- /// <param name="ex"></param>
- protected virtual void ServiceException( Exception ex ) { this.Logger( LogLevel.ERROR, "服務異常:" + ex.Message + " \r\n堆棧:" + ex.StackTrace ); }
- }
-
- #region 定時服務休眠計算類
- /// <summary>
- /// 文件生成時間配置
- /// </summary>
- public class TimerControl
- {
- #region 私有成員
- private TimerConfig Config { get; set; }
- #endregion
-
- #region 公共成員方法
- /// <summary>
- /// 構造函數
- /// </summary>
- /// <param name="config">配置參數</param>
- /// </param>
- public TimerControl( TimerConfig config )
- {
- Config = config;
- if ( Config == null ) throw new Exception( "定時器時間配置異常!" );
-
- switch ( Config.TimerMode )
- {
- case TimerMode.Date:
- if ( Config.MonthSeq < 1 || Config.MonthSeq > 12 )
- throw new Exception( "定時器時間配置異常(月份取值只能是1~12)!" );
- var dt = new DateTime( 2012, Config.MonthSeq, 1 ); // 之所以選2012,是因為他是閏年,因此2月有29天。
- var lastDay = GetLastDayByMonth( dt );
- if ( Config.DaySeq < 1 || Config.DaySeq > lastDay )
- throw new Exception( "定時器時間配置異常(" + Config.MonthSeq + "月份的天數取值只能是1~" + lastDay + ")!" );
- break;
- case TimerMode.Day: break;
- case TimerMode.Month:
- if ( Config.DaySeq < 1 || Config.DaySeq > 31 )
- throw new Exception( "定時器時間配置異常(天數取值只能是1~31)!" );
- break;
- case TimerMode.Week:
- if ( Config.DaySeq < 0 || Config.DaySeq > 6 )
- throw new Exception( "定時器時間配置異常(星期取值只能是0~6)!" );
- break;
- case TimerMode.LastDayOfMonth:
- if ( Config.DaySeq != 0 )
- {// 如果等於0的話,表示是每個月的最後一天。
- if ( Config.DaySeq < 1 || Config.DaySeq > 28 )
- throw new Exception( "定時器時間配置異常(倒數的天數只能是1~28,即倒數的第1天,第2天。。。有些月份並沒有29.30.31天,因此最大只允許倒數第28天)!" );
- Config.DaySeq -= 1;
- }
- break;
- case TimerMode.Year:
- if ( Config.DaySeq < 1 || Config.DaySeq > 366 )
- throw new Exception( "定時器時間配置異常(天數取值只能是1~366)!" );
- break;
- }
- }
-
- /// <summary>
- /// 判斷時間是否到了
- /// </summary>
- /// <returns>true時間已經到了,false時間還未到</returns>
- public bool TimeIsUp
- {
- get
- {
- DateTime dt = DateTime.Now;
- if ( CheckTimeIsUp( dt.TimeOfDay ) )
- {
- switch ( Config.TimerMode )
- {
- case TimerMode.Day: return true;
- case TimerMode.Date: return dt.Month == Config.MonthSeq && dt.Day == Config.DaySeq;
- case TimerMode.Week: return ( ( int )dt.DayOfWeek ) == Config.DaySeq;
- case TimerMode.Month: return dt.Day == Config.DaySeq;
- case TimerMode.Year: return dt.DayOfYear == Config.DaySeq;
- case TimerMode.LastDayOfMonth: return dt.Day == ( GetLastDayByMonth( dt ) - Config.DaySeq );
- default: return false;
- }
- }
- else
- return false;
- }
- }
-
- /// <summary>
- /// 時間是否到了
- /// </summary>
- /// <returns></returns>
- private bool CheckTimeIsUp( TimeSpan time )
- {
- var tmp = new TimeSpan( time.Hours, time.Minutes, time.Seconds );
- if ( Config.Times == null )
- return ( tmp.Ticks == 0 );
- else
- {
- foreach ( var t in Config.Times )
- {
- if ( t == tmp ) return true;
- }
- return false;
- }
- }
-
- /// <summary>
- /// 從現在起到下次時間到還有多少時間
- /// </summary>
- /// <returns>時間間隔</returns>
- public TimeSpan GetNextTimeUp()
- {
- ///目標時間
- DateTime _NextDateTime = this.GetNextDateTime(); // 保存下一次要執行的時間
- return _NextDateTime - DateTime.Now;
- }
-
- /// <summary>
- /// 獲取下一次指定配置的時間是多少
- /// </summary>
- /// <returns></returns>
- public DateTime GetNextDateTime()
- {
- var time = GetNextTimeConfig();
- DateTime dt = DateTime.Now;
- DateTime now, target;
- switch ( Config.TimerMode )
- {
- case TimerMode.Day:
- #region 每天指定某時執行一次
- now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, dt.Second );
- target = new DateTime( 1, 1, 1, time.Hours, time.Minutes, time.Seconds );
- if ( now.Ticks >= target.Ticks ) dt = dt.AddDays( 1.0 ); //如果當前時間小於指定時刻,則不需要加天
-
- dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
- #endregion
- break;
- case TimerMode.Month:
- #region 每月指定某天某時執行一次
- now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, dt.Second );
- target = new DateTime( 1, 1, Config.DaySeq, time.Hours, time.Minutes, time.Seconds ); // 1月有31天,所以可以接受任何合法的Day值(因為在賦值時已判斷1~31)
- if ( now.Ticks >= target.Ticks ) dt = dt.AddMonths( 1 );
-
-
- // 當前月份的指定天數執行過了,因此月份加上一個月,當月份加了一個月之後,很可能當前實現的Day值可能會變小(例:3月31號,加上一個月,則日期會變成,4月30號,而不會變成5月1號),
- // 因此需要判斷指定的this.Day是不是比Day大(月份的Day變小的唯一原因是因為月份加了一個月之後,那個月並沒有this.Day的天數),如果沒有該this.Day的天數。則需要為該月份再加一個月。
- // 加一個月份,則那下個月一定可以大於等於this.Day, 看看每個月的天數就可以斷定了,
- // 因為沒有連著兩個月的日期小於等於30的,只有連續兩個月是31天。其它就是間隔的出現(this.Day最大只可能為31)
- // 如此之後,接下來的dt=new DateTime時不為因為dt.Month的月份,因沒有this.Day天數而拋異常
- if ( Config.DaySeq > GetLastDayByMonth( dt ) ) dt = dt.AddMonths( 1 ); // 如此是為了確保dt.Month的月份一定有this.Day天(因此如果設置為每個月的31號執行的程序,就只會在1,3,5,7,8,10,12幾個月份會執行)
-
- dt = new DateTime( dt.Year, dt.Month, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );
- #endregion
- break;
- case TimerMode.LastDayOfMonth:
- #region 每個月倒數第N天的某時某刻執行一次
- var lastDaybymonth = GetLastDayByMonth( dt ) - Config.DaySeq;
- now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, dt.Second );
- target = new DateTime( 1, 1, lastDaybymonth, time.Hours, time.Minutes, time.Seconds ); // 1月有31天,所以可以接受任何合法的Day值(因為在賦值時已判斷1~31)
- if ( now.Ticks >= target.Ticks )
- {
- dt = dt.AddMonths( 1 );
- dt = new DateTime( dt.Year, dt.Month, GetLastDayByMonth( dt ) - Config.DaySeq, time.Hours, time.Minutes, time.Seconds );// 根據新月份求新月份的最後一天。
- }
- else
- dt = new DateTime( dt.Year, dt.Month, lastDaybymonth, time.Hours, time.Minutes, time.Seconds );
- #endregion
- break;
- case TimerMode.Week:
- #region 每星期指定星期某時執行一次
- int dow = ( int )dt.DayOfWeek;
- now = new DateTime( 1, 1, dow + 1, dt.Hour, dt.Minute, dt.Second );
- target = new DateTime( 1, 1, Config.DaySeq + 1, time.Hours, time.Minutes, time.Seconds );
-
- if ( now.Ticks >= target.Ticks )
- dt = dt.AddDays( Config.DaySeq - dow + 7 );
- else
- dt = dt.AddDays( Config.DaySeq - dow );
-
- dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
- #endregion
- break;
- case TimerMode.Date:
- #region 每年指定某月某日某時執行一次
- now = new DateTime( 4, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second );
-
- // 0004年閏年,可以支持2月29.因此選了0004, 這樣就不會在構造Target時異常,
- // 因為比較的關鍵不在年。所以,只要Now和Target的年份一樣就可以,設置成什麼年份無所謂
- target = new DateTime( 4, Config.MonthSeq, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );
-
- if ( now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
- if ( Config.MonthSeq == 2 && Config.DaySeq == 29 )
- {
- // 因為閏年的最大間隔是8年,平時是4年一閏,可是0096年閏完之後,下一個閏年就是0104年,因此。。。
- for ( int i = 0; i < 8; i++ )
- if ( DateTime.IsLeapYear( dt.Year + i ) )
- {
- dt = dt.AddYears( i );
- break;
- }
- }
-
- dt = new DateTime( dt.Year, Config.MonthSeq, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );
- #endregion
- break;
- case TimerMode.Year:
- #region 每年指定第N天某時執行一次
- now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, dt.Second );
- target = new DateTime( 1, 1, 1, time.Hours, time.Minutes, time.Seconds );
- if ( dt.DayOfYear > Config.DaySeq || dt.DayOfYear == Config.DaySeq && now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
- dt = dt.AddDays( Config.DaySeq - dt.DayOfYear );
-
- dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
- #endregion
- break;
- default:
- throw new Exception( "定時器時間配置異常!" );
- }
-
- return dt;
- }
-
- /// <summary>
- /// 獲取指定日期所在月份的最後一天
- /// </summary>
- /// <param name="dt"></param>
- /// <returns></returns>
- private int GetLastDayByMonth( DateTime dt )
- {
- switch ( dt.Month )
- {
- case 4:
- case 6:
- case 9:
- case 11:
- return 30;
- case 2:
- return DateTime.IsLeapYear( dt.Year ) ? 29 : 28;
- default:
- return 31;
- }
- }
-
- /// <summary>
- /// 獲取下一個時間點
- /// </summary>
- /// <returns></returns>
- private TimeSpan GetNextTimeConfig()
- {
- if ( Config.Times == null || Config.Times.Length == 0 )
- return new TimeSpan( 0 );
- else
- {
- var minData = TimeSpan.MaxValue; // 最小時間
- var minExecData = TimeSpan.MaxValue; // 大於當前時間的最小時間
- foreach ( var t in Config.Times )
- {
- if ( DateTime.Now.TimeOfDay < t && minExecData >= t ) // 找出比當前時間大的最小時間
- minExecData = t;
- if ( minData > t ) // 找出最小的一個時間,當前時間不參與運算
- minData = t;
- }
-
- if ( minExecData == TimeSpan.MaxValue ) // 如果找不到比當前時間大的最小時間,則選擇最小時間返回
- return minData;
- else
- return minExecData;
- }
- }
- #endregion
- }
- #endregion
-
- #region 系統配置實體類&配置讀取類
- /// <summary>
- /// 時間配置類
- /// </summary>
- public class ServiceTimerConfig
- {
- /// <summary>
- /// 默認配置
- /// </summary>
- public string Default { get; set; }
- /// <summary>
- /// 配置項
- /// </summary>
- public TimerConfig[] Config { get; set; }
- }
- /// <summary>
- /// 時間配置
- /// </summary>
- public class TimerConfig
- {
- /// <summary>
- /// 配置引用名
- /// </summary>
- public string RefName { get; set; }
-
- /// <summary>
- /// 時間模式
- /// timeMode取值如下:TimerMode.Month、TimerMode.Week、TimerMode.Week、TimerMode.Day、TimerMode.Date、TimerMode.Year
- /// </summary>
- public TimerMode TimerMode { get; set; }
-
- /// <summary>
- /// 指定某個時間算法的第幾天,第1天就為1
- /// TimerMode=TimerMode.Month 時, 該DaySeq表示每個月中的第幾天
- /// TimerMode=TimerMode.Week 時, 該DaySeq表示每個星期中的星期幾(0-星期天,其它用1-6表示)
- /// TimerMode=TimerMode.Day 時, 該值不需要設置
- /// TimerMode=TimerMode.Date 時, 該DaySeq表示每個日期中的天數,如:8月12號,則DaySeq為12,MonthSeq為8
- /// TimerMode=TimerMode.LastDayOfMonth 時, 該DaySeq表示每個月倒數第幾天
- /// TimerMode=TimerMode.Year 時, 該DaySeq表示每年中的第幾天
- /// </summary>
- public int DaySeq { get; set; }
-
- /// <summary>
- /// 當指定一年中某個月的某個日期時有用到如:指定一年中8月12號,則這裡的MonthSeq就應該為8
- /// </summary>
- public int MonthSeq { get; set; }
-
- /// <summary>
- /// 循環處理時間間隔(單位毫秒)
- /// </summary>
- public TimeSpan Interval { get; set; }
-
- /// <summary>
- /// 啟動延遲時間(單位毫秒)
- /// </summary>
- public TimeSpan Delay { get; set; }
-
- /// <summary>
- /// 時間設置
- /// </summary>
- public TimeSpan[] Times { get; set; }
- }
- /// <summary>
- /// 服務處理方法
- /// </summary>
- public enum TimerMode
- {
- /// <summary>
- /// 輪詢方式
- /// </summary>
- Interval = 0,
- /// <summary>
- /// 一個月中某個天數的指定時間
- /// </summary>
- Month = 1,
- /// <summary>
- /// 一周中的周幾的指定時間
- /// </summary>
- Week = 2,
- /// <summary>
- /// 一天中的指定時間
- /// </summary>
- Day = 3,
- /// <summary>
- /// 一年中第幾天的指定時間
- /// </summary>
- Year = 4,
- /// <summary>
- /// 一年中的指定日期的指定時間
- /// </summary>
- Date = 5,
- /// <summary>
- /// 每個月倒數第N天
- /// </summary>
- LastDayOfMonth,
- /// <summary>
- /// 未設置
- /// </summary>
- NoSet
- }
- /// <summary>
- /// 讀取配置數據
- /// </summary>
- public class ServiceTimerConfigManager : IConfigurationSectionHandler
- {
- private static Regex regEx = new Regex( @"^(?<h>[01]?\d|2[0-3])(?:[::](?<m>[0-5]\d?))?(?:[::](?<s>[0-5]\d?))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase );
-
- /// <summary>
- /// 請求服務配置
- /// </summary>
- public static ServiceTimerConfig ServiceConfig { get; set; }
- /// <summary>
- /// 靜態構造函數
- /// </summary>
- static ServiceTimerConfigManager()
- {
- ConfigurationManager.GetSection( "ServiceTimerConfig" );
- }
- /// <summary>
- /// 讀取自定義配置節
- /// </summary>
- /// <param name="parent">父結點</param>
- /// <param name="configContext">配置上下文</param>
- /// <param name="section">配置區</param>
- /// <returns></returns>
- object IConfigurationSectionHandler.Create( object parent, object configContext, XmlNode section )
- {
- ServiceConfig = new ServiceTimerConfig();
- var config = new List<TimerConfig>();
-
- foreach ( XmlNode node in section.ChildNodes )
- {
- if ( node.NodeType == XmlNodeType.Element )
- {
- switch ( node.Name.ToLower() )
- {
- case "default":
- ServiceConfig.Default = node.InnerText;
- break; ;
- case "config":
- var tmp = new TimerConfig();
- SetTimerConfigValue( tmp, node );
- config.Add( tmp );
- break; ;
- }
- }
- }
- ServiceConfig.Config = config.ToArray();
-
- return ServiceConfig;
- }
- /// <summary>
- /// 設置定時器值
- /// </summary>
- /// <param name="Config"></param>
- /// <param name="node"></param>
- private void SetTimerConfigValue( TimerConfig Config, XmlNode node )
- {
- int tmp, h, m, s;
- long longTmp;
- var times = new List<TimeSpan>();
-
- foreach ( XmlNode xn in node.ChildNodes )
- {
- if ( xn.NodeType == XmlNodeType.Element )
- {
- switch ( xn.Name.ToLower() )
- {
- case "refname":
- Config.RefName = xn.InnerText;
- break;
- case "timermode":
- if ( xn.InnerText != null )
- Config.TimerMode = ( TimerMode )Enum.Parse( typeof( TimerMode ), xn.InnerText );
- break;
- case "delay":
- Int64.TryParse( xn.InnerText, out longTmp );
- Config.Delay = new TimeSpan( longTmp * 10 * 1000L ); // Delay配置值為毫秒
- break;
- case "interval":
- Int64.TryParse( xn.InnerText, out longTmp ); // Interval配置值為毫秒
- Config.Interval = new TimeSpan( longTmp * 10 * 1000L );
- break;
- case "monthseq": // 月份
- Int32.TryParse( xn.InnerText, out tmp );
- Config.MonthSeq = tmp;
- break;
- case "dayseq": // 指定第幾天的序號
- Int32.TryParse( xn.InnerText, out tmp );
- Config.DaySeq = tmp;
- break;
- case "times":
- //還是用這個函數處理下一級的配置
- SetTimerConfigValue( Config, xn ); // 設置時間策略
- break;
- case "timevalue":
- var mc = regEx.Match( xn.InnerText );
- if ( !mc.Success ) throw new Exception( "時間配置不正確!" );
- Int32.TryParse( mc.Groups["h"].Value, out h );
- Int32.TryParse( mc.Groups["m"].Value, out m );
- Int32.TryParse( mc.Groups["s"].Value, out s );
- times.Add( new TimeSpan( h, m, s ) );
- break;
- }
- }
- }
- if ( times.Count != 0 )
- Config.Times = times.ToArray();
- }
- }
- #endregion
- }
C語言中 ^怎使用
a1 = 0x01; //0000 0001
a2 = 0x00; //0000 0000
a3 = 0x03; //0000 0011
a4 = 0x02; //0000 0010
b1 = a1 ^ a2; //0000 0001
b2 = a1 ^ a3; //0000 0010
b3 = a1 ^ a4; //0000 0011
^異或運算符,位值相同為0,不同為1,見上示例.
//
簡單實際問題舉例:
======\=======\=======
======a=======b=======
上面是2條電路,2個開關分別為a和b,打開狀態:\[1],關閉狀態:/[0].
若同時打開或者關閉,兩條電路均不通.
若a打開[1],b關閉[0],電路1通電
======\=======/=======
若a關閉[0],b打開[1],電路2通電
======/=======\=======
綜上,電路在a,b狀態相同時不通[0],在a,b不同時通電[1].
C語言中 ^怎使用
a1 = 0x01; //0000 0001
a2 = 0x00; //0000 0000
a3 = 0x03; //0000 0011
a4 = 0x02; //0000 0010
b1 = a1 ^ a2; //0000 0001
b2 = a1 ^ a3; //0000 0010
b3 = a1 ^ a4; //0000 0011
^異或運算符,位值相同為0,不同為1,見上示例.
//
簡單實際問題舉例:
======\=======\=======
======a=======b=======
上面是2條電路,2個開關分別為a和b,打開狀態:\[1],關閉狀態:/[0].
若同時打開或者關閉,兩條電路均不通.
若a打開[1],b關閉[0],電路1通電
======\=======/=======
若a關閉[0],b打開[1],電路2通電
======/=======\=======
綜上,電路在a,b狀態相同時不通[0],在a,b不同時通電[1].