#if NET40 || NET45 //|| !NET_4_6 using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; namespace System.Threading.Tasks { /// /// Provides methods for creating and manipulating tasks. /// /// /// /// TaskEx is a placeholder. /// public static class TaskEx { private const string ArgumentOutOfRange_TimeoutNonNegativeOrMinusOne = "The timeout must be non-negative or -1, and it must be less than or equal to Int32.MaxValue."; /// /// An already canceled task. /// private static readonly Task _preCanceledTask = ((Func)(() => { var tcs = new TaskCompletionSource(); tcs.TrySetCanceled(); return tcs.Task; }))(); /// /// An already completed task. /// private static readonly Task _preCompletedTask = FromResult(false); static TaskEx() { } /// /// Starts a Task that will complete after the specified due time. /// /// The delay in milliseconds before the returned task completes. /// /// The timed Task. /// /// The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. /// public static Task Delay(int dueTime) { return Delay(dueTime, CancellationToken.None); } /// /// Starts a Task that will complete after the specified due time. /// /// The delay before the returned task completes. /// /// The timed Task. /// /// The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. /// public static Task Delay(TimeSpan dueTime) { return Delay(dueTime, CancellationToken.None); } /// /// Starts a Task that will complete after the specified due time. /// /// The delay before the returned task completes.A CancellationToken that may be used to cancel the task before the due time occurs. /// /// The timed Task. /// /// The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. /// public static Task Delay(TimeSpan dueTime, CancellationToken cancellationToken) { var timeoutMs = (long)dueTime.TotalMilliseconds; if (timeoutMs < Timeout.Infinite || timeoutMs > int.MaxValue) throw new ArgumentOutOfRangeException("dueTime", ArgumentOutOfRange_TimeoutNonNegativeOrMinusOne); return Delay((int)timeoutMs, cancellationToken); } /// /// Starts a Task that will complete after the specified due time. /// /// The delay in milliseconds before the returned task completes.A CancellationToken that may be used to cancel the task before the due time occurs. /// /// The timed Task. /// /// The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. /// public static Task Delay(int dueTime, CancellationToken cancellationToken) { if (dueTime < -1) throw new ArgumentOutOfRangeException("dueTime", ArgumentOutOfRange_TimeoutNonNegativeOrMinusOne); if (cancellationToken.IsCancellationRequested) return _preCanceledTask; if (dueTime == 0) return _preCompletedTask; var tcs = new TaskCompletionSource(); var ctr = new CancellationTokenRegistration(); Timer timer = null; timer = new Timer(_ => { ctr.Dispose(); timer.Dispose(); tcs.TrySetResult(true); }, null, Timeout.Infinite, Timeout.Infinite); if (cancellationToken.CanBeCanceled) { ctr = cancellationToken.Register(() => { timer.Dispose(); tcs.TrySetCanceled(); }); } timer.Change(dueTime, Timeout.Infinite); return tcs.Task; } /// /// Creates an already completed from the specified result. /// /// The result from which to create the completed task. /// /// The completed task. /// public static Task FromResult(TResult result) { var completionSource = new TaskCompletionSource(result); completionSource.TrySetResult(result); return completionSource.Task; } /// /// Creates a task that runs the specified action. /// /// The action to execute asynchronously. /// /// A task that represents the completion of the action. /// /// The argument is null. public static Task Run(Action action) { return Run(action, CancellationToken.None); } /// /// Creates a task that runs the specified action. /// /// The action to execute.The CancellationToken to use to request cancellation of this task. /// /// A task that represents the completion of the action. /// /// The argument is null. public static Task Run(Action action, CancellationToken cancellationToken) { return Task.Factory.StartNew(action, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); } /// /// Creates a task that runs the specified function. /// /// The function to execute asynchronously. /// /// A task that represents the completion of the action. /// /// The argument is null. public static Task Run(Func function) { return Run(function, CancellationToken.None); } /// /// Creates a task that runs the specified function. /// /// The action to execute.The CancellationToken to use to cancel the task. /// /// A task that represents the completion of the action. /// /// The argument is null. public static Task Run(Func function, CancellationToken cancellationToken) { return Task.Factory.StartNew(function, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default); } /// /// Creates a task that runs the specified function. /// /// The action to execute asynchronously. /// /// A task that represents the completion of the action. /// /// The argument is null. public static Task Run(Func function) { return Run(function, CancellationToken.None); } /// /// Creates a task that runs the specified function. /// /// The function to execute.The CancellationToken to use to request cancellation of this task. /// /// A task that represents the completion of the function. /// /// The argument is null. public static Task Run(Func function, CancellationToken cancellationToken) { return Run(function, cancellationToken).Unwrap(); } /// /// Creates a task that runs the specified function. /// /// The function to execute asynchronously. /// /// A task that represents the completion of the action. /// /// The argument is null. public static Task Run(Func> function) { return Run(function, CancellationToken.None); } /// /// Creates a task that runs the specified function. /// /// The action to execute.The CancellationToken to use to cancel the task. /// /// A task that represents the completion of the action. /// /// The argument is null. public static Task Run(Func> function, CancellationToken cancellationToken) { return Run>(function, cancellationToken).Unwrap(); } /// /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. /// /// The Tasks to monitor for completion. /// /// A Task that represents the completion of all of the provided tasks. /// /// /// /// If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information /// about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned /// Task will also be canceled. /// /// /// The argument is null.The argument contains a null reference. public static Task WhenAll(params Task[] tasks) { return WhenAll((IEnumerable)tasks); } /// /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. /// /// The Tasks to monitor for completion. /// /// A Task that represents the completion of all of the provided tasks. /// /// /// /// If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information /// about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned /// Task will also be canceled. /// /// /// The argument is null.The argument contains a null reference. public static Task WhenAll(params Task[] tasks) { return WhenAll((IEnumerable>)tasks); } /// /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. /// /// The Tasks to monitor for completion. /// /// A Task that represents the completion of all of the provided tasks. /// /// /// /// If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information /// about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned /// Task will also be canceled. /// /// /// The argument is null.The argument contains a null reference. public static Task WhenAll(IEnumerable tasks) { return WhenAllCore(tasks, (Action>)((completedTasks, tcs) => tcs.TrySetResult(null))); } /// /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. /// /// The Tasks to monitor for completion. /// /// A Task that represents the completion of all of the provided tasks. /// /// /// /// If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information /// about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned /// Task will also be canceled. /// /// /// The argument is null.The argument contains a null reference. public static Task WhenAll(IEnumerable> tasks) { return WhenAllCore(tasks.Cast(), (completedTasks, tcs) => tcs.TrySetResult(completedTasks .Cast>() .Select(t => t.Result) .ToArray())); } /// /// Creates a Task that will complete when any of the tasks in the provided collection completes. /// /// The Tasks to be monitored. /// /// A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. /// /// /// /// /// Any Tasks that fault will need to have their exceptions observed elsewhere. /// /// The argument is null.The argument contains a null reference. public static Task WhenAny(params Task[] tasks) { return WhenAny((IEnumerable)tasks); } /// /// Creates a Task that will complete when any of the tasks in the provided collection completes. /// /// The Tasks to be monitored. /// /// A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. /// /// /// /// /// Any Tasks that fault will need to have their exceptions observed elsewhere. /// /// The argument is null.The argument contains a null reference. public static Task WhenAny(IEnumerable tasks) { if (tasks == null) throw new ArgumentNullException("tasks"); var tcs = new TaskCompletionSource(); Task.Factory.ContinueWhenAny(tasks as Task[] ?? tasks.ToArray(), tcs.TrySetResult, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); return tcs.Task; } /// /// Creates a Task that will complete when any of the tasks in the provided collection completes. /// /// The Tasks to be monitored. /// /// A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. /// /// /// /// /// Any Tasks that fault will need to have their exceptions observed elsewhere. /// /// The argument is null.The argument contains a null reference. public static Task> WhenAny(params Task[] tasks) { return WhenAny((IEnumerable>)tasks); } /// /// Creates a Task that will complete when any of the tasks in the provided collection completes. /// /// The Tasks to be monitored. /// /// A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. /// /// /// /// /// Any Tasks that fault will need to have their exceptions observed elsewhere. /// /// The argument is null.The argument contains a null reference. public static Task> WhenAny(IEnumerable> tasks) { if (tasks == null) throw new ArgumentNullException("tasks"); var tcs = new TaskCompletionSource>(); Task.Factory.ContinueWhenAny(tasks as Task[] ?? tasks.ToArray(), tcs.TrySetResult, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); return tcs.Task; } /// /// Creates an awaitable that asynchronously yields back to the current context when awaited. /// /// /// /// A context that, when awaited, will asynchronously transition back into the current context. /// If SynchronizationContext.Current is non-null, that is treated as the current context. /// Otherwise, TaskScheduler.Current is treated as the current context. /// /// public static YieldAwaitable Yield() { return new YieldAwaitable(); } /// /// Adds the target exception to the list, initializing the list if it's null. /// /// The list to which to add the exception and initialize if the list is null.The exception to add, and unwrap if it's an aggregate. private static void AddPotentiallyUnwrappedExceptions(ref List targetList, Exception exception) { var aggregateException = exception as AggregateException; if (targetList == null) targetList = new List(); if (aggregateException != null) targetList.Add(aggregateException.InnerExceptions.Count == 1 ? exception.InnerException : exception); else targetList.Add(exception); } /// /// Creates a Task that will complete only when all of the provided collection of Tasks has completed. /// /// The Tasks to monitor for completion.A callback invoked when all of the tasks complete successfully in the RanToCompletion state. /// This callback is responsible for storing the results into the TaskCompletionSource. /// /// /// A Task that represents the completion of all of the provided tasks. /// /// The argument is null.The argument contains a null reference. private static Task WhenAllCore(IEnumerable tasks, Action> setResultAction) { if (tasks == null) throw new ArgumentNullException("tasks"); var tcs = new TaskCompletionSource(); var taskArray = tasks as Task[] ?? tasks.ToArray(); if (taskArray.Length == 0) setResultAction(taskArray, tcs); else Task.Factory.ContinueWhenAll(taskArray, completedTasks => { List exceptions = null; var canceled = false; foreach (var task in completedTasks) { if (task.IsFaulted) AddPotentiallyUnwrappedExceptions(ref exceptions, task.Exception); else if (task.IsCanceled) canceled = true; } if (exceptions != null && exceptions.Count > 0) tcs.TrySetException(exceptions); else if (canceled) tcs.TrySetCanceled(); else setResultAction(completedTasks, tcs); }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); return tcs.Task; } } } #endif