如何让 Timer 在特定时间点触发?

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何让 Timer 在特定时间点触发?相关的知识,希望对你有一定的参考价值。

咨询区

  • Behrooz Karjoo

我的应用程序需要做一个 事件触发 的功能,它需要每天定时执行,比如说当天的 16点,我现在的做法是使用一个 timer 按秒轮询判断当前是否为 16:00, 虽然可以玩得转,但我想能不能实现那种 16:00 自动触发回调函数的模式,而不是现在无时无刻的轮询。

回答区

  • noontz

其实很简单,计算触发时间与当前时间的差值,然后将 差值 作为精确的延迟时间,带入到 Task.Delay 中即可,外面再套个 while(true) ,下面是我封装的代码。

/// <summary>
/// Utility class for triggering an event every 24 hours at a specified time of day
/// </summary>
public class DailyTrigger : IDisposable

   /// <summary>
   /// Time of day (from 00:00:00) to trigger
   /// </summary>
   TimeSpan TriggerHour  get; 

   /// <summary>
   /// Task cancellation token source to cancel delayed task on disposal
   /// </summary>
   CancellationTokenSource CancellationToken  get; set; 

   /// <summary>
   /// Reference to the running task
   /// </summary>
   Task RunningTask  get; set; 

   /// <summary>
   /// Initiator
   /// </summary>
   /// <param name="hour">The hour of the day to trigger</param>
   /// <param name="minute">The minute to trigger</param>
   /// <param name="second">The second to trigger</param>
   public DailyTrigger(int hour, int minute = 0, int second = 0)
   
       TriggerHour = new TimeSpan(hour, minute, second);
       CancellationToken = new CancellationTokenSource();
       RunningTask = Task.Run(async () => 
       
           while (true)
           
               var triggerTime = DateTime.Today + TriggerHour - DateTime.Now;
               if (triggerTime < TimeSpan.Zero)
                   triggerTime = triggerTime.Add(new TimeSpan(24, 0, 0));
               await Task.Delay(triggerTime, CancellationToken.Token);
               OnTimeTriggered?.Invoke();
           
       , CancellationToken.Token);
   

   /// <inheritdoc/>
   public void Dispose()
   
       CancellationToken?.Cancel();
       CancellationToken?.Dispose();
       CancellationToken = null;
       RunningTask?.Dispose();
       RunningTask = null;
   

   /// <summary>
   /// Triggers once every 24 hours on the specified time
   /// </summary>
   public event Action OnTimeTriggered;

   /// <summary>
   /// Finalized to ensure Dispose is called when out of scope
   /// </summary>
   ~DailyTrigger() => Dispose();

然后像下面这样使用。

void Main()

    var trigger = new DailyTrigger(16); // every day at 4:00pm

    trigger.OnTimeTriggered += () => 
    
        // Whatever
    ;  
    
    Console.ReadKey();

点评区

思路是个好思路,不过在正式的项目开发中,建议还是用 Quartz.NET 或者 HangFire 这种专业的调度框架,毕竟它支持强大的 Cron 表达式。

RecurringJob.AddOrUpdate(() => MyMethod(), "* 16 * * *");

以上是关于如何让 Timer 在特定时间点触发?的主要内容,如果未能解决你的问题,请参考以下文章

片段未附加到上下文 - 延迟的 UI 更改

VB.net 如何设定准确的1秒时间?

如何使用boost asio stable timer expiry获取执行时间点

如何在特定时间触发android中的后台服务?

如何在音轨中的特定点触发事件或回调?

如何从 Timer.Elapsed 事件触发另一个事件?