/// <summary> /// Creates a Task that will complete after a time delay. /// </summary> /// <param name="millisecondsDelay">The number of milliseconds to wait before completing the returned Task</param> /// <param name="cancellationToken">The cancellation token that will be checked prior to completing the returned Task</param> /// <returns>A Task that represents the time delay</returns> /// <exception cref="T:System.ArgumentOutOfRangeException"> /// The <paramref name="millisecondsDelay"/> is less than -1. /// </exception> /// <exception cref="T:System.ObjectDisposedException"> /// The provided <paramref name="cancellationToken"/> has already been disposed. /// </exception> /// <remarks> /// If the cancellation token is signaled before the specified time delay, then the Task is completed in /// Canceled state. Otherwise, the Task is completed in RanToCompletion state once the specified time /// delay has expired. /// </remarks> public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken) { // Throw on non-sensical time if (millisecondsDelay < -1) { throw new ArgumentOutOfRangeException(nameof(millisecondsDelay), "The value needs to be either -1 (signifying an infinite timeout), 0 or a positive integer."); } Contract.EndContractBlock(); // some short-cuts in case quick completion is in order if (cancellationToken.IsCancellationRequested) { // return a Task created as already-Canceled return(FromCancellation(cancellationToken)); } if (millisecondsDelay == 0) { // return a Task created as already-RanToCompletion return(CompletedTask); } var source = new TaskCompletionSource <bool>(); if (millisecondsDelay > 0) { var timeout = RootedTimeout.Launch ( () => { try { source.SetResult(true); } catch (InvalidOperationException exception) { // Already cancelled GC.KeepAlive(exception); } }, millisecondsDelay, cancellationToken ); source.Task.SetPromiseCheck(() => timeout.CheckRemaining()); } if (cancellationToken.CanBeCanceled) { cancellationToken.Register ( () => { try { source.SetCanceled(); } catch (InvalidOperationException exception) { // Already timeout GC.KeepAlive(exception); } } ); } return(source.Task); }
public static Task <TResult> Then <T, TResult>(this Task <T> task, Func <T, Task <TResult> > onFulfilled) { task.NotNull(nameof(task)); onFulfilled.NotNull(nameof(onFulfilled)); if (task.IsCompleted) { if (task.Exception?.InnerException != null) { return(Promise.Reject <TResult>(task.Exception.InnerExceptions)); } if (task.IsCanceled) { return(Promise.Cancel <TResult>()); } try { return(onFulfilled(task.Result)); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception e) #pragma warning restore CA1031 // Do not catch general exception types { return(Promise.Reject <TResult>(e)); } } var tcs = new TaskCompletionSource <TResult>(); task.ContinueWith(t => { if (t.Exception?.InnerException != null) { tcs.SetException(t.Exception.InnerExceptions); return; } if (t.IsCanceled) { tcs.SetCanceled(); return; } Task <TResult> fulfilledTask; try { fulfilledTask = onFulfilled(t.Result); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception e) #pragma warning restore CA1031 // Do not catch general exception types { tcs.SetException(e); return; } if (fulfilledTask.IsCompleted) { tcs.SetFromCompleted(fulfilledTask); return; } fulfilledTask.ContinueWith( ft => tcs.SetFromCompleted(ft), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); return(tcs.Task); }
/// <summary> /// Transitions the underlying task into the <see cref="SystemTasks.TaskStatus.Canceled"/> state. /// </summary> public static void SetCanceled(SystemTaskCompletionSource tcs) => tcs.SetCanceled();
public static Task Catch(this Task task, Func <Exception, Task> onRejected) { task.NotNull(nameof(task)); onRejected.NotNull(nameof(onRejected)); if (task.IsCompleted) { if (task.IsCanceled || task.Exception?.InnerException == null) { return(task); } try { return(onRejected(task.Exception.InnerException)); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception e) #pragma warning restore CA1031 // Do not catch general exception types { return(Promise.Reject(e)); } } var tcs = new TaskCompletionSource <bool>(); task.ContinueWith(t => { if (t.Exception?.InnerException == null) { if (t.IsCanceled) { tcs.SetCanceled(); return; } tcs.SetResult(true); return; } Task rejectedTask; try { rejectedTask = onRejected(t.Exception.InnerException); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception e) #pragma warning restore CA1031 // Do not catch general exception types { tcs.SetException(e); return; } if (rejectedTask.IsCompleted) { tcs.SetFromCompleted(rejectedTask); return; } rejectedTask.ContinueWith( rt => tcs.SetFromCompleted(rt), CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); return(tcs.Task); }
public static Task <T> Finally <T>(this Task <T> task, Func <Task> onFinally) { task.NotNull(nameof(task)); onFinally.NotNull(nameof(onFinally)); TaskCompletionSource <T> tcs; if (task.IsCompleted) { Task finallyTask; try { finallyTask = onFinally(); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception e) #pragma warning restore CA1031 // Do not catch general exception types { return(Promise.Reject <T>(e)); } if (finallyTask.IsCompleted) { if (finallyTask.Exception?.InnerException != null) { return(Promise.Reject <T>(finallyTask.Exception.InnerExceptions)); } return(finallyTask.IsCanceled ? Promise.Cancel <T>() : task); } tcs = new TaskCompletionSource <T>(); finallyTask.ContinueWith(ft => { if (ft.Exception?.InnerException != null) { tcs.SetException(ft.Exception.InnerExceptions); return; } if (ft.IsCanceled) { tcs.SetCanceled(); return; } tcs.SetFromCompleted(task); }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); return(tcs.Task); } tcs = new TaskCompletionSource <T>(); task.ContinueWith(t => { Task finallyTask; try { finallyTask = onFinally(); } #pragma warning disable CA1031 // Do not catch general exception types catch (Exception e) #pragma warning restore CA1031 // Do not catch general exception types { tcs.SetException(e); return; } if (finallyTask.IsCompleted) { if (finallyTask.Exception?.InnerException != null) { tcs.SetException(finallyTask.Exception.InnerExceptions); return; } if (finallyTask.IsCanceled) { tcs.SetCanceled(); return; } tcs.SetFromCompleted(t); return; } finallyTask.ContinueWith(ft => { if (ft.Exception?.InnerException != null) { tcs.SetException(ft.Exception.InnerExceptions); return; } if (ft.IsCanceled) { tcs.SetCanceled(); return; } tcs.SetFromCompleted(t); }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); return(tcs.Task); }