Scheduler.Async.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Reactive.Disposables;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace System.Reactive.Concurrency
  8. {
  9. public static partial class Scheduler
  10. {
  11. /// <summary>
  12. /// Yields execution of the current work item on the scheduler to another work item on the scheduler.
  13. /// The caller should await the result of calling Yield to schedule the remainder of the current work item (known as the continuation).
  14. /// </summary>
  15. /// <param name="scheduler">Scheduler to yield work on.</param>
  16. /// <returns>Scheduler operation object to await in order to schedule the continuation.</returns>
  17. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>
  18. public static SchedulerOperation Yield(this IScheduler scheduler)
  19. {
  20. if (scheduler == null)
  21. throw new ArgumentNullException(nameof(scheduler));
  22. return new SchedulerOperation(a => scheduler.Schedule(a), scheduler.GetCancellationToken());
  23. }
  24. /// <summary>
  25. /// Yields execution of the current work item on the scheduler to another work item on the scheduler.
  26. /// The caller should await the result of calling Yield to schedule the remainder of the current work item (known as the continuation).
  27. /// </summary>
  28. /// <param name="scheduler">Scheduler to yield work on.</param>
  29. /// <param name="cancellationToken">Cancellation token to cancel the continuation to run.</param>
  30. /// <returns>Scheduler operation object to await in order to schedule the continuation.</returns>
  31. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>
  32. public static SchedulerOperation Yield(this IScheduler scheduler, CancellationToken cancellationToken)
  33. {
  34. if (scheduler == null)
  35. throw new ArgumentNullException(nameof(scheduler));
  36. return new SchedulerOperation(a => scheduler.Schedule(a), cancellationToken);
  37. }
  38. /// <summary>
  39. /// Suspends execution of the current work item on the scheduler for the specified duration.
  40. /// The caller should await the result of calling Sleep to schedule the remainder of the current work item (known as the continuation) after the specified duration.
  41. /// </summary>
  42. /// <param name="scheduler">Scheduler to yield work on.</param>
  43. /// <param name="dueTime">Time when the continuation should run.</param>
  44. /// <returns>Scheduler operation object to await in order to schedule the continuation.</returns>
  45. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>
  46. public static SchedulerOperation Sleep(this IScheduler scheduler, TimeSpan dueTime)
  47. {
  48. if (scheduler == null)
  49. throw new ArgumentNullException(nameof(scheduler));
  50. return new SchedulerOperation(a => scheduler.Schedule(dueTime, a), scheduler.GetCancellationToken());
  51. }
  52. /// <summary>
  53. /// Suspends execution of the current work item on the scheduler for the specified duration.
  54. /// The caller should await the result of calling Sleep to schedule the remainder of the current work item (known as the continuation) after the specified duration.
  55. /// </summary>
  56. /// <param name="scheduler">Scheduler to yield work on.</param>
  57. /// <param name="dueTime">Time when the continuation should run.</param>
  58. /// <param name="cancellationToken">Cancellation token to cancel the continuation to run.</param>
  59. /// <returns>Scheduler operation object to await in order to schedule the continuation.</returns>
  60. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>
  61. public static SchedulerOperation Sleep(this IScheduler scheduler, TimeSpan dueTime, CancellationToken cancellationToken)
  62. {
  63. if (scheduler == null)
  64. throw new ArgumentNullException(nameof(scheduler));
  65. return new SchedulerOperation(a => scheduler.Schedule(dueTime, a), cancellationToken);
  66. }
  67. /// <summary>
  68. /// Suspends execution of the current work item on the scheduler until the specified due time.
  69. /// The caller should await the result of calling Sleep to schedule the remainder of the current work item (known as the continuation) at the specified due time.
  70. /// </summary>
  71. /// <param name="scheduler">Scheduler to yield work on.</param>
  72. /// <param name="dueTime">Time when the continuation should run.</param>
  73. /// <returns>Scheduler operation object to await in order to schedule the continuation.</returns>
  74. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>
  75. public static SchedulerOperation Sleep(this IScheduler scheduler, DateTimeOffset dueTime)
  76. {
  77. if (scheduler == null)
  78. throw new ArgumentNullException(nameof(scheduler));
  79. return new SchedulerOperation(a => scheduler.Schedule(dueTime, a), scheduler.GetCancellationToken());
  80. }
  81. /// <summary>
  82. /// Suspends execution of the current work item on the scheduler until the specified due time.
  83. /// The caller should await the result of calling Sleep to schedule the remainder of the current work item (known as the continuation) at the specified due time.
  84. /// </summary>
  85. /// <param name="scheduler">Scheduler to yield work on.</param>
  86. /// <param name="dueTime">Time when the continuation should run.</param>
  87. /// <param name="cancellationToken">Cancellation token to cancel the continuation to run.</param>
  88. /// <returns>Scheduler operation object to await in order to schedule the continuation.</returns>
  89. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> is null.</exception>
  90. public static SchedulerOperation Sleep(this IScheduler scheduler, DateTimeOffset dueTime, CancellationToken cancellationToken)
  91. {
  92. if (scheduler == null)
  93. throw new ArgumentNullException(nameof(scheduler));
  94. return new SchedulerOperation(a => scheduler.Schedule(dueTime, a), cancellationToken);
  95. }
  96. /// <summary>
  97. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  98. /// </summary>
  99. /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
  100. /// <param name="scheduler">Scheduler to schedule work on.</param>
  101. /// <param name="state">State to pass to the asynchronous method.</param>
  102. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  103. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  104. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  105. public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task> action)
  106. {
  107. if (scheduler == null)
  108. throw new ArgumentNullException(nameof(scheduler));
  109. if (action == null)
  110. throw new ArgumentNullException(nameof(action));
  111. return ScheduleAsync_<TState>(scheduler, state, action);
  112. }
  113. /// <summary>
  114. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  115. /// </summary>
  116. /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
  117. /// <param name="scheduler">Scheduler to schedule work on.</param>
  118. /// <param name="state">State to pass to the asynchronous method.</param>
  119. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  120. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  121. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  122. public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
  123. {
  124. if (scheduler == null)
  125. throw new ArgumentNullException(nameof(scheduler));
  126. if (action == null)
  127. throw new ArgumentNullException(nameof(action));
  128. return ScheduleAsync_<TState>(scheduler, state, action);
  129. }
  130. /// <summary>
  131. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  132. /// </summary>
  133. /// <param name="scheduler">Scheduler to schedule work on.</param>
  134. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  135. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  136. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  137. public static IDisposable ScheduleAsync(this IScheduler scheduler, Func<IScheduler, CancellationToken, Task> action)
  138. {
  139. if (scheduler == null)
  140. throw new ArgumentNullException(nameof(scheduler));
  141. if (action == null)
  142. throw new ArgumentNullException(nameof(action));
  143. return ScheduleAsync_(scheduler, default(object), (self, o, ct) => action(self, ct));
  144. }
  145. /// <summary>
  146. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  147. /// </summary>
  148. /// <param name="scheduler">Scheduler to schedule work on.</param>
  149. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  150. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  151. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  152. public static IDisposable ScheduleAsync(this IScheduler scheduler, Func<IScheduler, CancellationToken, Task<IDisposable>> action)
  153. {
  154. if (scheduler == null)
  155. throw new ArgumentNullException(nameof(scheduler));
  156. if (action == null)
  157. throw new ArgumentNullException(nameof(action));
  158. return ScheduleAsync_(scheduler, default(object), (self, o, ct) => action(self, ct));
  159. }
  160. /// <summary>
  161. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  162. /// </summary>
  163. /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
  164. /// <param name="scheduler">Scheduler to schedule work on.</param>
  165. /// <param name="state">State to pass to the asynchronous method.</param>
  166. /// <param name="dueTime">Relative time after which to execute the action.</param>
  167. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  168. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  169. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  170. public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, TimeSpan dueTime, Func<IScheduler, TState, CancellationToken, Task> action)
  171. {
  172. if (scheduler == null)
  173. throw new ArgumentNullException(nameof(scheduler));
  174. if (action == null)
  175. throw new ArgumentNullException(nameof(action));
  176. return ScheduleAsync_(scheduler, state, dueTime, action);
  177. }
  178. /// <summary>
  179. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  180. /// </summary>
  181. /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
  182. /// <param name="scheduler">Scheduler to schedule work on.</param>
  183. /// <param name="state">State to pass to the asynchronous method.</param>
  184. /// <param name="dueTime">Relative time after which to execute the action.</param>
  185. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  186. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  187. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  188. public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, TimeSpan dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
  189. {
  190. if (scheduler == null)
  191. throw new ArgumentNullException(nameof(scheduler));
  192. if (action == null)
  193. throw new ArgumentNullException(nameof(action));
  194. return ScheduleAsync_(scheduler, state, dueTime, action);
  195. }
  196. /// <summary>
  197. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  198. /// </summary>
  199. /// <param name="scheduler">Scheduler to schedule work on.</param>
  200. /// <param name="dueTime">Relative time after which to execute the action.</param>
  201. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  202. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  203. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  204. public static IDisposable ScheduleAsync(this IScheduler scheduler, TimeSpan dueTime, Func<IScheduler, CancellationToken, Task> action)
  205. {
  206. if (scheduler == null)
  207. throw new ArgumentNullException(nameof(scheduler));
  208. if (action == null)
  209. throw new ArgumentNullException(nameof(action));
  210. return ScheduleAsync_(scheduler, default(object), dueTime, (self, o, ct) => action(self, ct));
  211. }
  212. /// <summary>
  213. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  214. /// </summary>
  215. /// <param name="scheduler">Scheduler to schedule work on.</param>
  216. /// <param name="dueTime">Relative time after which to execute the action.</param>
  217. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  218. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  219. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  220. public static IDisposable ScheduleAsync(this IScheduler scheduler, TimeSpan dueTime, Func<IScheduler, CancellationToken, Task<IDisposable>> action)
  221. {
  222. if (scheduler == null)
  223. throw new ArgumentNullException(nameof(scheduler));
  224. if (action == null)
  225. throw new ArgumentNullException(nameof(action));
  226. return ScheduleAsync_(scheduler, default(object), dueTime, (self, o, ct) => action(self, ct));
  227. }
  228. /// <summary>
  229. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  230. /// </summary>
  231. /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
  232. /// <param name="scheduler">Scheduler to schedule work on.</param>
  233. /// <param name="state">State to pass to the asynchronous method.</param>
  234. /// <param name="dueTime">Absolute time at which to execute the action.</param>
  235. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  236. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  237. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  238. public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task> action)
  239. {
  240. if (scheduler == null)
  241. throw new ArgumentNullException(nameof(scheduler));
  242. if (action == null)
  243. throw new ArgumentNullException(nameof(action));
  244. return ScheduleAsync_(scheduler, state, dueTime, action);
  245. }
  246. /// <summary>
  247. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  248. /// </summary>
  249. /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
  250. /// <param name="scheduler">Scheduler to schedule work on.</param>
  251. /// <param name="state">State to pass to the asynchronous method.</param>
  252. /// <param name="dueTime">Absolute time at which to execute the action.</param>
  253. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  254. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  255. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  256. public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
  257. {
  258. if (scheduler == null)
  259. throw new ArgumentNullException(nameof(scheduler));
  260. if (action == null)
  261. throw new ArgumentNullException(nameof(action));
  262. return ScheduleAsync_(scheduler, state, dueTime, action);
  263. }
  264. /// <summary>
  265. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  266. /// </summary>
  267. /// <param name="scheduler">Scheduler to schedule work on.</param>
  268. /// <param name="dueTime">Absolute time at which to execute the action.</param>
  269. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  270. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  271. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  272. public static IDisposable ScheduleAsync(this IScheduler scheduler, DateTimeOffset dueTime, Func<IScheduler, CancellationToken, Task> action)
  273. {
  274. if (scheduler == null)
  275. throw new ArgumentNullException(nameof(scheduler));
  276. if (action == null)
  277. throw new ArgumentNullException(nameof(action));
  278. return ScheduleAsync_(scheduler, default(object), dueTime, (self, o, ct) => action(self, ct));
  279. }
  280. /// <summary>
  281. /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.
  282. /// </summary>
  283. /// <param name="scheduler">Scheduler to schedule work on.</param>
  284. /// <param name="dueTime">Absolute time at which to execute the action.</param>
  285. /// <param name="action">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>
  286. /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>
  287. /// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is null.</exception>
  288. public static IDisposable ScheduleAsync(this IScheduler scheduler, DateTimeOffset dueTime, Func<IScheduler, CancellationToken, Task<IDisposable>> action)
  289. {
  290. if (scheduler == null)
  291. throw new ArgumentNullException(nameof(scheduler));
  292. if (action == null)
  293. throw new ArgumentNullException(nameof(action));
  294. return ScheduleAsync_(scheduler, default(object), dueTime, (self, o, ct) => action(self, ct));
  295. }
  296. private static IDisposable ScheduleAsync_<TState>(IScheduler scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task> action)
  297. {
  298. return scheduler.Schedule(state, (self, s) => InvokeAsync(self, s, action));
  299. }
  300. private static IDisposable ScheduleAsync_<TState>(IScheduler scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
  301. {
  302. return scheduler.Schedule(state, (self, s) => InvokeAsync(self, s, action));
  303. }
  304. private static IDisposable ScheduleAsync_<TState>(IScheduler scheduler, TState state, TimeSpan dueTime, Func<IScheduler, TState, CancellationToken, Task> action)
  305. {
  306. return scheduler.Schedule(state, dueTime, (self, s) => InvokeAsync(self, s, action));
  307. }
  308. private static IDisposable ScheduleAsync_<TState>(IScheduler scheduler, TState state, TimeSpan dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
  309. {
  310. return scheduler.Schedule(state, dueTime, (self, s) => InvokeAsync(self, s, action));
  311. }
  312. private static IDisposable ScheduleAsync_<TState>(IScheduler scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task> action)
  313. {
  314. return scheduler.Schedule(state, dueTime, (self, s) => InvokeAsync(self, s, action));
  315. }
  316. private static IDisposable ScheduleAsync_<TState>(IScheduler scheduler, TState state, DateTimeOffset dueTime, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
  317. {
  318. return scheduler.Schedule(state, dueTime, (self, s) => InvokeAsync(self, s, action));
  319. }
  320. private static IDisposable InvokeAsync<TState>(IScheduler self, TState s, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)
  321. {
  322. var c = new CancellationDisposable();
  323. var d = new SingleAssignmentDisposable();
  324. action(new CancelableScheduler(self, c.Token), s, c.Token).ContinueWith(t =>
  325. {
  326. if (t.IsCanceled)
  327. return;
  328. if (t.Exception != null)
  329. t.Exception.Handle(e => e is OperationCanceledException);
  330. d.Disposable = t.Result;
  331. }, TaskContinuationOptions.ExecuteSynchronously);
  332. return StableCompositeDisposable.Create(c, d);
  333. }
  334. private static IDisposable InvokeAsync<TState>(IScheduler self, TState s, Func<IScheduler, TState, CancellationToken, Task> action)
  335. {
  336. return InvokeAsync(self, s, (self_, state, ct) => action(self_, state, ct).ContinueWith(_ => Disposable.Empty));
  337. }
  338. private static CancellationToken GetCancellationToken(this IScheduler scheduler)
  339. {
  340. var cs = scheduler as CancelableScheduler;
  341. return cs != null ? cs.Token : CancellationToken.None;
  342. }
  343. class CancelableScheduler : IScheduler
  344. {
  345. private readonly IScheduler _scheduler;
  346. private readonly CancellationToken _cancellationToken;
  347. public CancelableScheduler(IScheduler scheduler, CancellationToken cancellationToken)
  348. {
  349. _scheduler = scheduler;
  350. _cancellationToken = cancellationToken;
  351. }
  352. public CancellationToken Token
  353. {
  354. get { return _cancellationToken; }
  355. }
  356. public DateTimeOffset Now
  357. {
  358. get { return _scheduler.Now; }
  359. }
  360. public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
  361. {
  362. return _scheduler.Schedule(state, action);
  363. }
  364. public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
  365. {
  366. return _scheduler.Schedule(state, dueTime, action);
  367. }
  368. public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
  369. {
  370. return _scheduler.Schedule(state, dueTime, action);
  371. }
  372. }
  373. }
  374. }