private static Task <TOuterResult> ThenImpl <TTask, TOuterResult>(this TTask task, Func <TTask, Task <TOuterResult> > continuation, CancellationToken cancellationToken, bool runSynchronously)
            where TTask : Task
        {
            // Stay on the same thread if we can
            if (task.IsCompleted)
            {
                if (task.IsFaulted)
                {
                    return(TaskHelpers.FromErrors <TOuterResult>(task.Exception.InnerExceptions));
                }
                if (task.IsCanceled || cancellationToken.IsCancellationRequested)
                {
                    return(TaskHelpers.Canceled <TOuterResult>());
                }
                if (task.Status == TaskStatus.RanToCompletion)
                {
                    try
                    {
                        return(continuation(task));
                    }
                    catch (Exception ex)
                    {
                        return(TaskHelpers.FromError <TOuterResult>(ex));
                    }
                }
            }

            // Split into a continuation method so that we don't create a closure unnecessarily
            return(ThenImplContinuation(task, continuation, cancellationToken, runSynchronously));
        }
        /// <summary>
        /// Changes the return value of a task to the given result, if the task ends in the RanToCompletion state.
        /// This potentially imposes an extra ContinueWith to convert a non-completed task, so use this with caution.
        /// </summary>
        internal static Task <TResult> ToTask <TResult>(this Task task, CancellationToken cancellationToken = default(CancellationToken), TResult result = default(TResult))
        {
            if (task == null)
            {
                return(null);
            }

            // Stay on the same thread if we can
            if (task.IsCompleted)
            {
                if (task.IsFaulted)
                {
                    return(TaskHelpers.FromErrors <TResult>(task.Exception.InnerExceptions));
                }
                if (task.IsCanceled || cancellationToken.IsCancellationRequested)
                {
                    return(TaskHelpers.Canceled <TResult>());
                }
                if (task.Status == TaskStatus.RanToCompletion)
                {
                    return(TaskHelpers.FromResult(result));
                }
            }

            // Split into a continuation method so that we don't create a closure unnecessarily
            return(ToTaskContinuation(task, result));
        }
        public static Task <TResult> ToTask <TResult>(this Task task,
                                                      CancellationToken cancellationToken = default(CancellationToken), TResult result = default(TResult))
        {
            if (task == null)
            {
                return(null);
            }

            if (task.IsCompleted)
            {
                if (task.IsFaulted)
                {
                    return(TaskHelpers.FromErrors <TResult>(task.Exception.InnerExceptions));
                }
                if (task.IsCanceled || cancellationToken.IsCancellationRequested)
                {
                    return(TaskHelpers.Canceled <TResult>());
                }
                if (task.Status == TaskStatus.RanToCompletion)
                {
                    return(TaskHelpers.FromResult(result));
                }
            }

            return(ToTaskContinuation(task, result));
        }
        private static Task <TOuterResult> ThenImpl <TTask, TOuterResult>(this TTask task,
                                                                          Func <TTask, Task <TOuterResult> > continuation, CancellationToken cancellationToken, bool runSynchronously)
            where TTask : Task
        {
            if (task.IsCompleted)
            {
                if (task.IsFaulted)
                {
                    return(TaskHelpers.FromErrors <TOuterResult>(task.Exception.InnerExceptions));
                }
                if (task.IsCanceled || cancellationToken.IsCancellationRequested)
                {
                    return(TaskHelpers.Canceled <TOuterResult>());
                }
                if (task.Status == TaskStatus.RanToCompletion)
                {
                    try
                    {
                        return(continuation(task));
                    }
                    catch (Exception ex)
                    {
                        return(TaskHelpers.FromError <TOuterResult>(ex));
                    }
                }
            }

            return(ThenImplContinuation(task, continuation, cancellationToken, runSynchronously));
        }
Example #5
0
        public void FromErrors_Generic_ReturnsFaultedTaskWithGivenExceptions()
        {
            var exceptions = new[] { new Exception(), new InvalidOperationException() };

            Task <string> result = TaskHelpers.FromErrors <string>(exceptions);

            Assert.NotNull(result);
            Assert.True(result.IsFaulted);
            Assert.Equal(exceptions, result.Exception.InnerExceptions.ToArray());
        }
        internal static Task <TOuterResult> CastFromobject <TOuterResult>(this Task <object> task)
        {
            // Stay on the same thread if we can
            if (task.IsCompleted)
            {
                if (task.IsFaulted)
                {
                    return(TaskHelpers.FromErrors <TOuterResult>(task.Exception.InnerExceptions));
                }
                if (task.IsCanceled)
                {
                    return(TaskHelpers.Canceled <TOuterResult>());
                }
                if (task.Status == TaskStatus.RanToCompletion)
                {
                    try
                    {
                        return(TaskHelpers.FromResult <TOuterResult>((TOuterResult)task.Result));
                    }
                    catch (Exception exception)
                    {
                        return(TaskHelpers.FromError <TOuterResult>(exception));
                    }
                }
            }

            TaskCompletionSource <TOuterResult> tcs = new TaskCompletionSource <TOuterResult>();

            // schedule a synchronous task to cast: no need to worry about sync context or try/catch
            task.ContinueWith(innerTask =>
            {
                if (innerTask.IsFaulted)
                {
                    tcs.SetException(innerTask.Exception.InnerExceptions);
                }
                else if (innerTask.IsCanceled)
                {
                    tcs.SetCanceled();
                }
                else
                {
                    try
                    {
                        tcs.SetResult((TOuterResult)innerTask.Result);
                    }
                    catch (Exception exception)
                    {
                        tcs.SetException(exception);
                    }
                }
            }, TaskContinuationOptions.ExecuteSynchronously);

            return(tcs.Task);
        }
        public static Task <TOuterResult> CastFromObject <TOuterResult>(this Task <object> task)
        {
            if (task.IsCompleted)
            {
                if (task.IsFaulted)
                {
                    return(TaskHelpers.FromErrors <TOuterResult>(task.Exception.InnerExceptions));
                }
                if (task.IsCanceled)
                {
                    return(TaskHelpers.Canceled <TOuterResult>());
                }
                if (task.Status == TaskStatus.RanToCompletion)
                {
                    try
                    {
                        return(TaskHelpers.FromResult((TOuterResult)task.Result));
                    }
                    catch (Exception exception)
                    {
                        return(TaskHelpers.FromError <TOuterResult>(exception));
                    }
                }
            }

            var tcs = new TaskCompletionSource <TOuterResult>();

            task.ContinueWith(innerTask =>
            {
                if (innerTask.IsFaulted)
                {
                    tcs.SetException(innerTask.Exception.InnerExceptions);
                }
                else if (innerTask.IsCanceled)
                {
                    tcs.SetCanceled();
                }
                else
                {
                    try
                    {
                        tcs.SetResult((TOuterResult)innerTask.Result);
                    }
                    catch (Exception exception)
                    {
                        tcs.SetException(exception);
                    }
                }
            }, TaskContinuationOptions.ExecuteSynchronously);

            return(tcs.Task);
        }
        private static Task <TOuterResult> ThenImplContinuation <TOuterResult, TTask>(TTask task, Func <TTask, Task <TOuterResult> > continuation, CancellationToken cancellationToken)
            where TTask : Task
        {
            SynchronizationContext syncContext = SynchronizationContext.Current;

            return(task.ContinueWith(innerTask =>
            {
                if (innerTask.IsFaulted)
                {
                    return TaskHelpers.FromErrors <TOuterResult>(innerTask.Exception.InnerExceptions);
                }
                if (innerTask.IsCanceled || cancellationToken.IsCancellationRequested)
                {
                    return TaskHelpers.Canceled <TOuterResult>();
                }

                TaskCompletionSource <Task <TOuterResult> > tcs = new TaskCompletionSource <Task <TOuterResult> >();
                if (syncContext != null)
                {
                    syncContext.Post(state =>
                    {
                        try
                        {
                            tcs.TrySetResult(continuation(task));
                        }
                        catch (Exception ex)
                        {
                            tcs.TrySetException(ex);
                        }
                    }, state: null);
                }
                else
                {
                    tcs.TrySetResult(continuation(task));
                }
                return tcs.Task.FastUnwrap();
            }).FastUnwrap());
        }
        public static Task <object> CastToObject(this Task task)
        {
            if (task.IsCompleted)
            {
                if (task.IsFaulted)
                {
                    return(TaskHelpers.FromErrors <object>(task.Exception.InnerExceptions));
                }
                if (task.IsCanceled)
                {
                    return(TaskHelpers.Canceled <object>());
                }
                if (task.Status == TaskStatus.RanToCompletion)
                {
                    return(TaskHelpers.FromResult((object)null));
                }
            }

            var tcs = new TaskCompletionSource <object>();

            task.ContinueWith(innerTask =>
            {
                if (innerTask.IsFaulted)
                {
                    tcs.SetException(innerTask.Exception.InnerExceptions);
                }
                else if (innerTask.IsCanceled)
                {
                    tcs.SetCanceled();
                }
                else
                {
                    tcs.SetResult(null);
                }
            }, TaskContinuationOptions.ExecuteSynchronously);

            return(tcs.Task);
        }