如何在C#的特定时间每天调用一个方法?

Vim*_*987 72 c# methods scheduled-tasks winforms

我搜索了SO并找到了关于Quartz.net的答案.但它似乎对我的项目来说太大了.我想要一个等效的解决方案,但更简单和(最好)代码内(不需要外部库).如何在特定时间每天调用一种方法?

我需要添加一些关于此的信息:

  • 最简单(也很丑陋)的方法是每隔一分钟检查一次时间并在适当的时候调用方法

我想要一种更有效的方法来做到这一点,不需要经常检查时间,并且我可以控制是否完成了工作.如果方法失败(由于任何问题),程序应该知道写入日志/发送电子邮件.这就是我需要调用方法而不是安排工作的原因.

我发现这个解决方案在Java中用Java定时调用一个方法.在C#中是否有类似的方式?

编辑:我做到了这一点.我在void Main()中添加了一个参数,并创建了一个bat(由Windows Task Scheduler安排)以使用此参数运行程序.程序运行,完成工作,然后退出.如果作业失败,则能够写入日志和发送电子邮件.这种方法很符合我的要求:)

mar*_*c_s 74

  • 创建一个可以满足您需求的控制台应用
  • 使用Windows" 计划任务 "功能可以在您需要运行该控制台应用程序时执行该控制台应用程序

这真的是你所需要的!

更新:如果您想在应用内执行此操作,您有以下几种选择:

  • Windows窗体应用程序中,您可以点击该Application.Idle事件并检查是否已达到当天的时间来调用您的方法.仅当您的应用不忙于其他内容时才会调用此方法.快速检查你的目标时间是否已经达到,不应该给你的应用带来太多压力,我认为...
  • 在ASP.NET Web应用程序中,有"模拟"发送预定事件的方法 - 请查看此CodeProject文章
  • 当然,您也可以在任何.NET应用程序中简单地"自己动手" - 查看此CodeProject文章以获取示例实现

更新#2:如果你想每60分钟检查一次,你可以创建一个每60分钟唤醒一次的计时器,如果时间到了,它会调用该方法.

像这样的东西:

using System.Timers;

const double interval60Minutes = 60 * 60 * 1000; // milliseconds to one hour

Timer checkForTime = new Timer(interval60Minutes);
checkForTime.Elapsed += new ElapsedEventHandler(checkForTime_Elapsed);
checkForTime.Enabled = true;
Run Code Online (Sandbox Code Playgroud)

然后在你的事件处理程序中:

void checkForTime_Elapsed(object sender, ElapsedEventArgs e)
{
    if (timeIsReady())
    {
       SendEmail();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • timeIsReady()调用有什么作用? (3认同)
  • 非常好的、简单、简短、干净的解决方案,直到今天在 Windows 10 和 .Net 4.7.2 中都表现出色!谢谢。 (2认同)

Max*_*sky 9

每当我构建需要此类功能的应用程序时,我总是通过我找到的简单.NET库使用Windows任务计划程序.

有关示例代码和更多解释,参阅我对类似问题的回答.


jan*_*y02 9

我创建了一个易于使用的简单调度程序,您不需要使用外部库.TaskScheduler是一个单例,可以对定时器进行引用,因此定时器不会被垃圾回收,它可以安排多个任务.您可以设置第一次运行(小时和分钟),如果在调度时此时间超过了当时的第二天的调度开始.但是自定义代码很容易.

安排新任务非常简单.示例:在11:52,第一个任务是每15个secunds,第二个例子是每5个secunds.对于每日执行,将24设置为3参数.

TaskScheduler.Instance.ScheduleTask(11, 52, 0.00417, 
    () => 
    {
        Debug.WriteLine("task1: " + DateTime.Now);
        //here write the code that you want to schedule
    });

TaskScheduler.Instance.ScheduleTask(11, 52, 0.00139,
    () =>
    {
        Debug.WriteLine("task2: " + DateTime.Now);
        //here write the code that you want to schedule
    });
Run Code Online (Sandbox Code Playgroud)

我的调试窗口:

task2: 07.06.2017 11:52:00
task1: 07.06.2017 11:52:00
task2: 07.06.2017 11:52:05
task2: 07.06.2017 11:52:10
task1: 07.06.2017 11:52:15
task2: 07.06.2017 11:52:15
task2: 07.06.2017 11:52:20
task2: 07.06.2017 11:52:25
...
Run Code Online (Sandbox Code Playgroud)

只需将此类添加到您的项目中:

public class TaskScheduler
{
    private static TaskScheduler _instance;
    private List<Timer> timers = new List<Timer>();

    private TaskScheduler() { }

    public static TaskScheduler Instance => _instance ?? (_instance = new TaskScheduler());

    public void ScheduleTask(int hour, int min, double intervalInHour, Action task)
    {
        DateTime now = DateTime.Now;
        DateTime firstRun = new DateTime(now.Year, now.Month, now.Day, hour, min, 0, 0);
        if (now > firstRun)
        {
            firstRun = firstRun.AddDays(1);
        }

        TimeSpan timeToGo = firstRun - now;
        if (timeToGo <= TimeSpan.Zero)
        {
            timeToGo = TimeSpan.Zero;
        }

        var timer = new Timer(x =>
        {
            task.Invoke();
        }, null, timeToGo, TimeSpan.FromHours(intervalInHour));

        timers.Add(timer);
    }
}
Run Code Online (Sandbox Code Playgroud)


Cou*_*y D 8

正如其他人所说,您可以使用控制台应用程序在计划时运行.其他人没有说的是你可以在这个应用程序中触发你在主应用程序中等待的跨进程EventWaitHandle.

控制台应用:

class Program
{
    static void Main(string[] args)
    {
        EventWaitHandle handle = 
            new EventWaitHandle(true, EventResetMode.ManualReset, "GoodMutexName");
        handle.Set();
    }
}
Run Code Online (Sandbox Code Playgroud)

主要应用:

private void Form1_Load(object sender, EventArgs e)
{
    // Background thread, will die with application
    ThreadPool.QueueUserWorkItem((dumby) => EmailWait());
}

private void EmailWait()
{
    EventWaitHandle handle = 
        new EventWaitHandle(false, EventResetMode.ManualReset, "GoodMutexName");

    while (true)
    {
        handle.WaitOne();

        SendEmail();

        handle.Reset();
    }
}
Run Code Online (Sandbox Code Playgroud)


Gin*_*ino 8

这是使用 TPL 执行此操作的方法。无需创建/处置计时器等:

void ScheduleSomething()
{

    var runAt = DateTime.Today + TimeSpan.FromHours(16);

    if (runAt <= DateTime.Now)
    {
        DoSomething();
    }
    else
    {
        var delay = runAt - DateTime.Now;
        System.Threading.Tasks.Task.Delay(delay).ContinueWith(_ => DoSomething());
    }

}

void DoSomething()
{
    // do somethig
}
Run Code Online (Sandbox Code Playgroud)