使用C#Reactive Extensions在特定时间调用函数

时间:2014-12-13 23:05:25

标签: c# system.reactive

是否可以使用Reactive Extensions在特定时间调用函数?

例如,如果我想在每天早上9点和下午1点调用方法foo(),我可以使用Timer类每隔几秒检查一次是上午9点或下午1点,还是{{1功能。但有更有效的方法吗?所以我不是每隔几秒就检查是否有时间调用foo(),而是一个可以在适当的时候调用foo()的observable。

1 个答案:

答案 0 :(得分:6)

只需使用接受DateTimeOffset值的Timer重载即可。您可以使用DeferRepeat创建"绝对间隔"。

Observable.Defer(() => 
    DateTime.Now.Hour < 9
  ? Observable.Timer(DateTime.Today.AddHours(9))
  : DateTime.Now.Hour < 13
  ? Observable.Timer(DateTime.Today.AddHours(13))
  : Observable.Timer(DateTime.Today.AddDays(1).AddHours(9)))
          .Repeat()
          .Subscribe(...);

Rx automatically ensures尽可能地在指定的确切日期和时间发出通知,即使是关于定时器漂移以及系统时钟在计时器持续时间过去之前是否发生变化。 / p>

这是一种可以进一步概括问题的扩展方法。

用法:

Observable2.Daily(TimeSpan.FromHours(9), TimeSpan.FromHours(13)).Subscribe(...);

定义:

public static partial class Observable2
{
  public static IObservable<long> Daily(params TimeSpan[] times)
  {
    Contract.Requires(times != null);
    Contract.Requires(Contract.ForAll(times, time => time > TimeSpan.Zero));
    Contract.Requires(Contract.ForAll(times, time => time.TotalDays < 1));

    return Daily(Scheduler.Default, times);
  }

  public static IObservable<long> Daily(IScheduler scheduler, params TimeSpan[] times)
  {
    Contract.Requires(times != null);
    Contract.Requires(Contract.ForAll(times, time => time > TimeSpan.Zero));
    Contract.Requires(Contract.ForAll(times, time => time.TotalDays < 1));

    if (times.Length == 0)
      return Observable.Never<long>();

    // Do not sort in place.
    var sortedTimes = times.ToList();

    sortedTimes.Sort();

    return Observable.Defer(() =>
      {
        var now = DateTime.Now;

        var next = sortedTimes.FirstOrDefault(time => now.TimeOfDay < time);

        var date = next > TimeSpan.Zero
                 ? now.Date.Add(next)
                 : now.Date.AddDays(1).Add(sortedTimes[0]);

        Debug.WriteLine("Next @" + date + " from " + sortedTimes.Aggregate("", (s, t) => s + t + ", "));

        return Observable.Timer(date, scheduler);
      })
      .Repeat()
      .Scan(-1L, (n, _) => n + 1);
  }
}

<强>更新

如果你想要更多&#34;功能性&#34;根据Jeroen Mostert的回答,在你的方法中,根据迭代器块将输入定义为无限序列,然后你可以使用Generate,如下所示。

Observable.Generate(
  GetScheduleTimes().GetEnumerator(), 
  e => e.MoveNext(), 
  e => e, 
  e => e.Current, 
  e => e.Current);

Jeroen Mostert的回答(已删除)提供了GetScheduleTimes的示例实现,但基本上它只是一个迭代器块,产生了DateTimeOffset的无限序列while循环中的值,每个循环递增值&#39;一天一天。