--- /dev/null
+//--------------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// File: TaskFactoryExtensions_Delayed.cs
+//
+//--------------------------------------------------------------------------
+
+namespace System.Threading.Tasks
+{
+ public static partial class TaskFactoryExtensions
+ {
+ #region TaskFactory No Action
+ /// <summary>Creates a Task that will complete after the specified delay.</summary>
+ /// <param name="factory">The TaskFactory.</param>
+ /// <param name="millisecondsDelay">The delay after which the Task should transition to RanToCompletion.</param>
+ /// <returns>A Task that will be completed after the specified duration.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory, int millisecondsDelay)
+ {
+ return StartNewDelayed(factory, millisecondsDelay, CancellationToken.None);
+ }
+
+ /// <summary>Creates a Task that will complete after the specified delay.</summary>
+ /// <param name="factory">The TaskFactory.</param>
+ /// <param name="millisecondsDelay">The delay after which the Task should transition to RanToCompletion.</param>
+ /// <param name="cancellationToken">The cancellation token that can be used to cancel the timed task.</param>
+ /// <returns>A Task that will be completed after the specified duration and that's cancelable with the specified token.</returns>
+ public static Task StartNewDelayed(this TaskFactory factory, int millisecondsDelay, CancellationToken cancellationToken)
+ {
+ // Validate arguments
+ if (factory == null) throw new ArgumentNullException("factory");
+ if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
+
+ // Create the timed task
+ var tcs = new TaskCompletionSource<object>(factory.CreationOptions);
+ var ctr = default(CancellationTokenRegistration);
+
+ // Create the timer but don't start it yet. If we start it now,
+ // it might fire before ctr has been set to the right registration.
+ var timer = new Timer(self =>
+ {
+ // Clean up both the cancellation token and the timer, and try to transition to completed
+ ctr.Dispose();
+ ((Timer)self).Dispose();
+ tcs.TrySetResult(null);
+ });
+
+ // Register with the cancellation token.
+ if (cancellationToken.CanBeCanceled)
+ {
+ // When cancellation occurs, cancel the timer and try to transition to canceled.
+ // There could be a race, but it's benign.
+ ctr = cancellationToken.Register(() =>
+ {
+ timer.Dispose();
+ tcs.TrySetCanceled();
+ });
+ }
+
+ // Start the timer and hand back the task...
+ timer.Change(millisecondsDelay, Timeout.Infinite);
+ return tcs.Task;
+ }
+ #endregion
+
+ #region TaskFactory with Action
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="action">The delegate executed by the task.</param>
+ /// <returns>The created Task.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory,
+ int millisecondsDelay, Action action)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, action, factory.CancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="action">The delegate executed by the task.</param>
+ /// <param name="creationOptions">Options that control the task's behavior.</param>
+ /// <returns>The created Task.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory,
+ int millisecondsDelay, Action action,
+ TaskCreationOptions creationOptions)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, action, factory.CancellationToken, creationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="action">The delegate executed by the task.</param>
+ /// <param name="cancellationToken">The cancellation token to assign to the created Task.</param>
+ /// <returns>The created Task.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory,
+ int millisecondsDelay, Action action,
+ CancellationToken cancellationToken)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, action, cancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="action">The delegate executed by the task.</param>
+ /// <param name="cancellationToken">The cancellation token to assign to the created Task.</param>
+ /// <param name="creationOptions">Options that control the task's behavior.</param>
+ /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
+ /// <returns>The created Task.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory,
+ int millisecondsDelay, Action action,
+ CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
+ if (action == null) throw new ArgumentNullException("action");
+ if (scheduler == null) throw new ArgumentNullException("scheduler");
+
+ return factory
+ .StartNewDelayed(millisecondsDelay, cancellationToken)
+ .ContinueWith(_ => action(), cancellationToken, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler);
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="action">The delegate executed by the task.</param>
+ /// <param name="state">An object provided to the delegate.</param>
+ /// <returns>The created Task.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory,
+ int millisecondsDelay, Action<object> action, object state)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, action, state, factory.CancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="action">The delegate executed by the task.</param>
+ /// <param name="state">An object provided to the delegate.</param>
+ /// <param name="creationOptions">Options that control the task's behavior.</param>
+ /// <returns>The created Task.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory,
+ int millisecondsDelay, Action<object> action, object state,
+ TaskCreationOptions creationOptions)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, action, state, factory.CancellationToken, creationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="action">The delegate executed by the task.</param>
+ /// <param name="state">An object provided to the delegate.</param>
+ /// <param name="cancellationToken">The cancellation token to assign to the created Task.</param>
+ /// <returns>The created Task.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory,
+ int millisecondsDelay, Action<object> action, object state,
+ CancellationToken cancellationToken)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, action, state, cancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="action">The delegate executed by the task.</param>
+ /// <param name="state">An object provided to the delegate.</param>
+ /// <param name="cancellationToken">The cancellation token to assign to the created Task.</param>
+ /// <param name="creationOptions">Options that control the task's behavior.</param>
+ /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
+ /// <returns>The created Task.</returns>
+ public static Task StartNewDelayed(
+ this TaskFactory factory,
+ int millisecondsDelay, Action<object> action, object state,
+ CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
+ if (action == null) throw new ArgumentNullException("action");
+ if (scheduler == null) throw new ArgumentNullException("scheduler");
+
+ // Create the task that will be returned; workaround for no ContinueWith(..., state) overload.
+ var result = new TaskCompletionSource<object>(state);
+
+ // Delay a continuation to run the action
+ factory
+ .StartNewDelayed(millisecondsDelay, cancellationToken)
+ .ContinueWith(t =>
+ {
+ if (t.IsCanceled) result.TrySetCanceled();
+ else
+ {
+ try
+ {
+ action(state);
+ result.TrySetResult(null);
+ }
+ catch (Exception exc) { result.TrySetException(exc); }
+ }
+ }, scheduler);
+
+ // Return the task
+ return result.Task;
+ }
+ #endregion
+
+ #region TaskFactory<TResult> with Func
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="function">The delegate executed by the task.</param>
+ /// <returns>The created Task.</returns>
+ public static Task<TResult> StartNewDelayed<TResult>(
+ this TaskFactory<TResult> factory,
+ int millisecondsDelay, Func<TResult> function)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, function, factory.CancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="function">The delegate executed by the task.</param>
+ /// <param name="creationOptions">Options that control the task's behavior.</param>
+ /// <returns>The created Task.</returns>
+ public static Task<TResult> StartNewDelayed<TResult>(
+ this TaskFactory<TResult> factory,
+ int millisecondsDelay, Func<TResult> function,
+ TaskCreationOptions creationOptions)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, function, factory.CancellationToken, creationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="function">The delegate executed by the task.</param>
+ /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
+ /// <returns>The created Task.</returns>
+ public static Task<TResult> StartNewDelayed<TResult>(
+ this TaskFactory<TResult> factory,
+ int millisecondsDelay, Func<TResult> function,
+ CancellationToken cancellationToken)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, function, cancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="function">The delegate executed by the task.</param>
+ /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
+ /// <param name="creationOptions">Options that control the task's behavior.</param>
+ /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
+ /// <returns>The created Task.</returns>
+ public static Task<TResult> StartNewDelayed<TResult>(
+ this TaskFactory<TResult> factory,
+ int millisecondsDelay, Func<TResult> function,
+ CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
+ if (function == null) throw new ArgumentNullException("function");
+ if (scheduler == null) throw new ArgumentNullException("scheduler");
+
+ // Create the trigger and the timer to start it
+ var tcs = new TaskCompletionSource<object>();
+ var timer = new Timer(obj => ((TaskCompletionSource<object>)obj).SetResult(null),
+ tcs, millisecondsDelay, Timeout.Infinite);
+
+ // Return a task that executes the function when the trigger fires
+ return tcs.Task.ContinueWith(_ =>
+ {
+ timer.Dispose();
+ return function();
+ }, cancellationToken, ContinuationOptionsFromCreationOptions(creationOptions), scheduler);
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="function">The delegate executed by the task.</param>
+ /// <param name="state">An object provided to the delegate.</param>
+ /// <returns>The created Task.</returns>
+ public static Task<TResult> StartNewDelayed<TResult>(
+ this TaskFactory<TResult> factory,
+ int millisecondsDelay, Func<object, TResult> function, object state)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, function, state, factory.CancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="function">The delegate executed by the task.</param>
+ /// <param name="state">An object provided to the delegate.</param>
+ /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
+ /// <returns>The created Task.</returns>
+ public static Task<TResult> StartNewDelayed<TResult>(
+ this TaskFactory<TResult> factory,
+ int millisecondsDelay, Func<object, TResult> function, object state,
+ CancellationToken cancellationToken)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, function, state, cancellationToken, factory.CreationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="function">The delegate executed by the task.</param>
+ /// <param name="state">An object provided to the delegate.</param>
+ /// <param name="creationOptions">Options that control the task's behavior.</param>
+ /// <returns>The created Task.</returns>
+ public static Task<TResult> StartNewDelayed<TResult>(
+ this TaskFactory<TResult> factory,
+ int millisecondsDelay, Func<object, TResult> function, object state,
+ TaskCreationOptions creationOptions)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ return StartNewDelayed(factory, millisecondsDelay, function, state, factory.CancellationToken, creationOptions, factory.GetTargetScheduler());
+ }
+
+ /// <summary>Creates and schedules a task for execution after the specified time delay.</summary>
+ /// <param name="factory">The factory to use to create the task.</param>
+ /// <param name="millisecondsDelay">The delay after which the task will be scheduled.</param>
+ /// <param name="function">The delegate executed by the task.</param>
+ /// <param name="state">An object provided to the delegate.</param>
+ /// <param name="cancellationToken">The CancellationToken to assign to the Task.</param>
+ /// <param name="creationOptions">Options that control the task's behavior.</param>
+ /// <param name="scheduler">The scheduler to which the Task will be scheduled.</param>
+ /// <returns>The created Task.</returns>
+ public static Task<TResult> StartNewDelayed<TResult>(
+ this TaskFactory<TResult> factory,
+ int millisecondsDelay, Func<object, TResult> function, object state,
+ CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler)
+ {
+ if (factory == null) throw new ArgumentNullException("factory");
+ if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");
+ if (function == null) throw new ArgumentNullException("action");
+ if (scheduler == null) throw new ArgumentNullException("scheduler");
+
+ // Create the task that will be returned
+ var result = new TaskCompletionSource<TResult>(state);
+ Timer timer = null;
+
+ // Create the task that will run the user's function
+ var functionTask = new Task<TResult>(function, state, creationOptions);
+
+ // When the function task completes, transfer the results to the returned task
+ functionTask.ContinueWith(t =>
+ {
+ result.SetFromTask(t);
+ timer.Dispose();
+ }, cancellationToken, ContinuationOptionsFromCreationOptions(creationOptions) | TaskContinuationOptions.ExecuteSynchronously, scheduler);
+
+ // Start the timer for the trigger
+ timer = new Timer(obj => ((Task)obj).Start(scheduler),
+ functionTask, millisecondsDelay, Timeout.Infinite);
+
+ return result.Task;
+ }
+ #endregion
+ }
+}
\ No newline at end of file