Skip to content

Instantly share code, notes, and snippets.

@micdenny
Created July 14, 2014 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micdenny/b5b196917fd24d6798e5 to your computer and use it in GitHub Desktop.
Save micdenny/b5b196917fd24d6798e5 to your computer and use it in GitHub Desktop.
TaskHelpers
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Threading.Tasks
{
internal static class TaskHelpers
{
private readonly static Task _defaultCompleted;
private readonly static Task<object> _completedTaskReturningNull;
static TaskHelpers()
{
TaskHelpers._defaultCompleted = TaskHelpers.FromResult<TaskHelpers.AsyncVoid>(new TaskHelpers.AsyncVoid());
TaskHelpers._completedTaskReturningNull = TaskHelpers.FromResult<object>(null);
}
internal static Task Canceled()
{
return TaskHelpers.CancelCache<TaskHelpers.AsyncVoid>.Canceled;
}
internal static Task<TResult> Canceled<TResult>()
{
return TaskHelpers.CancelCache<TResult>.Canceled;
}
internal static Task Completed()
{
return TaskHelpers._defaultCompleted;
}
internal static Task FromError(Exception exception)
{
return TaskHelpers.FromError<TaskHelpers.AsyncVoid>(exception);
}
internal static Task<TResult> FromError<TResult>(Exception exception)
{
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
taskCompletionSource.SetException(exception);
return taskCompletionSource.Task;
}
internal static Task FromErrors(IEnumerable<Exception> exceptions)
{
return TaskHelpers.FromErrors<TaskHelpers.AsyncVoid>(exceptions);
}
internal static Task<TResult> FromErrors<TResult>(IEnumerable<Exception> exceptions)
{
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
taskCompletionSource.SetException(exceptions);
return taskCompletionSource.Task;
}
internal static Task<TResult> FromResult<TResult>(TResult result)
{
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
taskCompletionSource.SetResult(result);
return taskCompletionSource.Task;
}
internal static Task Iterate(IEnumerable<Task> asyncIterator, CancellationToken cancellationToken = null, bool disposeEnumerator = true)
{
Task task;
Task task1;
IEnumerator<Task> enumerator = null;
try
{
enumerator = asyncIterator.GetEnumerator();
Task task2 = TaskHelpers.IterateImpl(enumerator, cancellationToken);
if (!disposeEnumerator || enumerator == null)
{
task1 = task2;
}
else
{
bool flag = true;
IEnumerator<Task> enumerator1 = enumerator;
task1 = task2.Finally(new Action(enumerator1.Dispose), flag);
}
task = task1;
}
catch (Exception exception)
{
task = TaskHelpers.FromError(exception);
}
return task;
}
internal static Task IterateImpl(IEnumerator<Task> enumerator, CancellationToken cancellationToken)
{
Task current;
Task task;
try
{
do
{
if (cancellationToken.IsCancellationRequested)
{
task = TaskHelpers.Canceled();
return task;
}
else if (enumerator.MoveNext())
{
current = enumerator.Current;
}
else
{
task = TaskHelpers.Completed();
return task;
}
}
while (current.Status == TaskStatus.RanToCompletion);
task = (current.IsCanceled || current.IsFaulted ? current : TaskHelpers.IterateImplIncompleteTask(enumerator, current, cancellationToken));
}
catch (Exception exception)
{
task = TaskHelpers.FromError(exception);
}
return task;
}
internal static Task IterateImplIncompleteTask(IEnumerator<Task> enumerator, Task currentTask, CancellationToken cancellationToken)
{
return currentTask.Then(() => TaskHelpers.IterateImpl(enumerator, cancellationToken), new CancellationToken(), false);
}
internal static Task<object> NullResult()
{
return TaskHelpers._completedTaskReturningNull;
}
public static Task RunSynchronously(Action action, CancellationToken token = null)
{
Task task;
if (token.IsCancellationRequested)
{
return TaskHelpers.Canceled();
}
try
{
action();
task = TaskHelpers.Completed();
}
catch (Exception exception)
{
task = TaskHelpers.FromError(exception);
}
return task;
}
internal static Task<TResult> RunSynchronously<TResult>(Func<TResult> func, CancellationToken cancellationToken = null)
{
Task<TResult> task;
if (cancellationToken.IsCancellationRequested)
{
return TaskHelpers.Canceled<TResult>();
}
try
{
task = TaskHelpers.FromResult<TResult>(func());
}
catch (Exception exception)
{
task = TaskHelpers.FromError<TResult>(exception);
}
return task;
}
internal static Task<TResult> RunSynchronously<TResult>(Func<Task<TResult>> func, CancellationToken cancellationToken = null)
{
Task<TResult> task;
if (cancellationToken.IsCancellationRequested)
{
return TaskHelpers.Canceled<TResult>();
}
try
{
task = func();
}
catch (Exception exception)
{
task = TaskHelpers.FromError<TResult>(exception);
}
return task;
}
internal static bool SetIfTaskFailed<TResult>(this TaskCompletionSource<TResult> tcs, Task source)
{
switch (source.Status)
{
case TaskStatus.Canceled:
case TaskStatus.Faulted:
{
return tcs.TrySetFromTask<TResult>(source);
}
}
return false;
}
internal static bool TrySetFromTask<TResult>(this TaskCompletionSource<TResult> tcs, Task source)
{
if (source.Status == TaskStatus.Canceled)
{
return tcs.TrySetCanceled();
}
if (source.Status == TaskStatus.Faulted)
{
return tcs.TrySetException(source.Exception.InnerExceptions);
}
if (source.Status != TaskStatus.RanToCompletion)
{
return false;
}
Task<TResult> task = source as Task<TResult>;
return tcs.TrySetResult((task == null ? default(TResult) : task.Result));
}
internal static bool TrySetFromTask<TResult>(this TaskCompletionSource<Task<TResult>> tcs, Task source)
{
if (source.Status == TaskStatus.Canceled)
{
return tcs.TrySetCanceled();
}
if (source.Status == TaskStatus.Faulted)
{
return tcs.TrySetException(source.Exception.InnerExceptions);
}
if (source.Status != TaskStatus.RanToCompletion)
{
return false;
}
Task<Task<TResult>> task = source as Task<Task<TResult>>;
if (task != null)
{
return tcs.TrySetResult(task.Result);
}
Task<TResult> task1 = source as Task<TResult>;
if (task1 != null)
{
return tcs.TrySetResult(task1);
}
return tcs.TrySetResult(TaskHelpers.FromResult<TResult>(default(TResult)));
}
private struct AsyncVoid
{
}
private static class CancelCache<TResult>
{
public readonly static Task<TResult> Canceled;
static CancelCache()
{
TaskHelpers.CancelCache<TResult>.Canceled = TaskHelpers.CancelCache<TResult>.GetCancelledTask();
}
private static Task<TResult> GetCancelledTask()
{
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
taskCompletionSource.SetCanceled();
return taskCompletionSource.Task;
}
}
}
}
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
namespace System.Threading.Tasks
{
internal static class TaskHelpersExtensions
{
private static Task<TaskHelpersExtensions.AsyncVoid> _defaultCompleted;
private readonly static Action<Task> _rethrowWithNoStackLossDelegate;
static TaskHelpersExtensions()
{
TaskHelpersExtensions._defaultCompleted = TaskHelpers.FromResult<TaskHelpersExtensions.AsyncVoid>(new TaskHelpersExtensions.AsyncVoid());
TaskHelpersExtensions._rethrowWithNoStackLossDelegate = TaskHelpersExtensions.GetRethrowWithNoStackLossDelegate();
}
internal static Task<TOuterResult> CastFromObject<TOuterResult>(this Task<object> task)
{
Task<TOuterResult> task1;
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
{
task1 = TaskHelpers.FromResult<TOuterResult>((TOuterResult)task.Result);
}
catch (Exception exception1)
{
task1 = TaskHelpers.FromError<TOuterResult>(exception1);
}
return task1;
}
}
TaskCompletionSource<TOuterResult> taskCompletionSource = new TaskCompletionSource<TOuterResult>();
task.ContinueWith((Task<object> innerTask) => {
if (innerTask.IsFaulted)
{
taskCompletionSource.SetException(innerTask.Exception.InnerExceptions);
return;
}
if (innerTask.IsCanceled)
{
taskCompletionSource.SetCanceled();
return;
}
try
{
taskCompletionSource.SetResult((TOuterResult)innerTask.Result);
}
catch (Exception exception)
{
taskCompletionSource.SetException(exception);
}
}, TaskContinuationOptions.ExecuteSynchronously);
return taskCompletionSource.Task;
}
internal 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);
}
}
TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();
task.ContinueWith((Task innerTask) => {
if (innerTask.IsFaulted)
{
taskCompletionSource.SetException(innerTask.Exception.InnerExceptions);
return;
}
if (innerTask.IsCanceled)
{
taskCompletionSource.SetCanceled();
return;
}
taskCompletionSource.SetResult(null);
}, TaskContinuationOptions.ExecuteSynchronously);
return taskCompletionSource.Task;
}
internal static Task<object> CastToObject<T>(this Task<T> 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>(task.Result);
}
}
TaskCompletionSource<object> taskCompletionSource = new TaskCompletionSource<object>();
task.ContinueWith((Task<T> innerTask) => {
if (innerTask.IsFaulted)
{
taskCompletionSource.SetException(innerTask.Exception.InnerExceptions);
return;
}
if (innerTask.IsCanceled)
{
taskCompletionSource.SetCanceled();
return;
}
taskCompletionSource.SetResult(innerTask.Result);
}, TaskContinuationOptions.ExecuteSynchronously);
return taskCompletionSource.Task;
}
internal static Task Catch(this Task task, Func<CatchInfo, CatchInfoBase<Task>.CatchResult> continuation, CancellationToken cancellationToken = null)
{
if (task.Status == TaskStatus.RanToCompletion)
{
return task;
}
return task.CatchImpl<TaskHelpersExtensions.AsyncVoid>(() => continuation(new CatchInfo(task)).Task.ToTask<TaskHelpersExtensions.AsyncVoid>(new CancellationToken(), new TaskHelpersExtensions.AsyncVoid()), cancellationToken);
}
internal static Task<TResult> Catch<TResult>(this Task<TResult> task, Func<CatchInfo<TResult>, CatchInfoBase<Task<TResult>>.CatchResult> continuation, CancellationToken cancellationToken = null)
{
if (task.Status == TaskStatus.RanToCompletion)
{
return task;
}
return task.CatchImpl<TResult>(() => continuation(new CatchInfo<TResult>(task)).Task, cancellationToken);
}
private static Task<TResult> CatchImpl<TResult>(this Task task, Func<Task<TResult>> continuation, CancellationToken cancellationToken)
{
Task<TResult> task1;
if (task.IsCompleted)
{
if (task.IsFaulted)
{
try
{
Task<TResult> task2 = continuation();
if (task2 == null)
{
throw new InvalidOperationException("You must set the Task property of the CatchInfo returned from the TaskHelpersExtensions.Catch continuation.");
}
task1 = task2;
}
catch (Exception exception)
{
task1 = TaskHelpers.FromError<TResult>(exception);
}
return task1;
}
if (task.IsCanceled || cancellationToken.IsCancellationRequested)
{
return TaskHelpers.Canceled<TResult>();
}
if (task.Status == TaskStatus.RanToCompletion)
{
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
taskCompletionSource.TrySetFromTask<TResult>(task);
return taskCompletionSource.Task;
}
}
return TaskHelpersExtensions.CatchImplContinuation<TResult>(task, continuation);
}
private static Task<TResult> CatchImplContinuation<TResult>(Task task, Func<Task<TResult>> continuation)
{
SynchronizationContext current = SynchronizationContext.Current;
TaskCompletionSource<Task<TResult>> taskCompletionSource = new TaskCompletionSource<Task<TResult>>();
task.ContinueWith<bool>((Task innerTask) => taskCompletionSource.TrySetFromTask<TResult>(innerTask), TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
task.ContinueWith((Task innerTask) => {
if (current != null)
{
current.Post((object state) => {
try
{
Task<TResult> task2 = continuation();
if (task2 == null)
{
throw new InvalidOperationException("You cannot return null from the TaskHelpersExtensions.Catch continuation. You must return a valid task or throw an exception.");
}
taskCompletionSource.TrySetResult(task2);
}
catch (Exception exception)
{
taskCompletionSource.TrySetException(exception);
}
}, null);
return;
}
try
{
Task<TResult> task1 = continuation();
if (task1 == null)
{
throw new InvalidOperationException("You cannot return null from the TaskHelpersExtensions.Catch continuation. You must return a valid task or throw an exception.");
}
taskCompletionSource.TrySetResult(task1);
}
catch (Exception exception1)
{
taskCompletionSource.TrySetException(exception1);
}
}, TaskContinuationOptions.OnlyOnFaulted);
return taskCompletionSource.Task.FastUnwrap<TResult>();
}
internal static Task CopyResultToCompletionSource<TResult>(this Task task, TaskCompletionSource<TResult> tcs, TResult completionResult)
{
return task.CopyResultToCompletionSourceImpl<Task, TResult>(tcs, (Task innerTask) => completionResult);
}
internal static Task CopyResultToCompletionSource<TResult>(this Task<TResult> task, TaskCompletionSource<TResult> tcs)
{
return task.CopyResultToCompletionSourceImpl<Task<TResult>, TResult>(tcs, (Task<TResult> innerTask) => innerTask.Result);
}
private static Task CopyResultToCompletionSourceImpl<TTask, TResult>(this TTask task, TaskCompletionSource<TResult> tcs, Func<TTask, TResult> resultThunk)
where TTask : Task
{
if (!task.IsCompleted)
{
return TaskHelpersExtensions.CopyResultToCompletionSourceImplContinuation<TTask, TResult>(task, tcs, resultThunk);
}
switch (task.Status)
{
case TaskStatus.RanToCompletion:
{
tcs.TrySetResult(resultThunk(task));
break;
}
case TaskStatus.Canceled:
case TaskStatus.Faulted:
{
tcs.TrySetFromTask<TResult>(task);
break;
}
}
return TaskHelpers.Completed();
}
private static Task CopyResultToCompletionSourceImplContinuation<TTask, TResult>(TTask task, TaskCompletionSource<TResult> tcs, Func<TTask, TResult> resultThunk)
where TTask : Task
{
return task.ContinueWith((Task innerTask) => {
switch (innerTask.Status)
{
case TaskStatus.RanToCompletion:
{
tcs.TrySetResult(resultThunk(task));
return;
}
case TaskStatus.Canceled:
case TaskStatus.Faulted:
{
tcs.TrySetFromTask<TResult>(innerTask);
return;
}
default:
{
return;
}
}
}, TaskContinuationOptions.ExecuteSynchronously);
}
internal static Task FastUnwrap(this Task<Task> task)
{
Task result;
if (task.Status == TaskStatus.RanToCompletion)
{
result = task.Result;
}
else
{
result = null;
}
return result ?? task.Unwrap();
}
internal static Task<TResult> FastUnwrap<TResult>(this Task<Task<TResult>> task)
{
Task<TResult> result;
if (task.Status == TaskStatus.RanToCompletion)
{
result = task.Result;
}
else
{
result = null;
}
return result ?? task.Unwrap<TResult>();
}
internal static Task Finally(this Task task, Action continuation, bool runSynchronously = false)
{
Task task1;
if (!task.IsCompleted)
{
return TaskHelpersExtensions.FinallyImplContinuation<TaskHelpersExtensions.AsyncVoid>(task, continuation, runSynchronously);
}
try
{
continuation();
task1 = task;
}
catch (Exception exception1)
{
Exception exception = exception1;
task.MarkExceptionsObserved();
task1 = TaskHelpers.FromError(exception);
}
return task1;
}
internal static Task<TResult> Finally<TResult>(this Task<TResult> task, Action continuation, bool runSynchronously = false)
{
Task<TResult> task1;
if (!task.IsCompleted)
{
return TaskHelpersExtensions.FinallyImplContinuation<TResult>(task, continuation, runSynchronously);
}
try
{
continuation();
task1 = task;
}
catch (Exception exception1)
{
Exception exception = exception1;
task.MarkExceptionsObserved();
task1 = TaskHelpers.FromError<TResult>(exception);
}
return task1;
}
private static Task<TResult> FinallyImplContinuation<TResult>(Task task, Action continuation, bool runSynchronously = false)
{
SynchronizationContext current = SynchronizationContext.Current;
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
task.ContinueWith((Task innerTask) => {
try
{
if (current == null)
{
continuation();
taskCompletionSource.TrySetFromTask<TResult>(innerTask);
}
else
{
current.Post((object state) => {
try
{
continuation();
taskCompletionSource.TrySetFromTask<TResult>(innerTask);
}
catch (Exception exception1)
{
Exception exception = exception1;
innerTask.MarkExceptionsObserved();
taskCompletionSource.SetException(exception);
}
}, null);
}
}
catch (Exception exception3)
{
Exception exception2 = exception3;
innerTask.MarkExceptionsObserved();
taskCompletionSource.TrySetException(exception2);
}
}, (runSynchronously ? TaskContinuationOptions.ExecuteSynchronously : TaskContinuationOptions.None));
return taskCompletionSource.Task;
}
private static Action<Task> GetRethrowWithNoStackLossDelegate()
{
MethodInfo method = typeof(Task).GetMethod("GetAwaiter", Type.EmptyTypes);
if (method != null)
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(Task));
MethodCallExpression methodCallExpression = Expression.Call(parameterExpression, method);
MethodCallExpression methodCallExpression1 = Expression.Call(methodCallExpression, "GetResult", Type.EmptyTypes, new Expression[0]);
ParameterExpression[] parameterExpressionArray = new ParameterExpression[] { parameterExpression };
return Expression.Lambda<Action<Task>>(methodCallExpression1, parameterExpressionArray).Compile();
}
Func<Exception, Exception> func = null;
try
{
if (AppDomain.CurrentDomain.IsFullyTrusted)
{
ParameterExpression parameterExpression1 = Expression.Parameter(typeof(Exception));
MethodCallExpression methodCallExpression2 = Expression.Call(parameterExpression1, "PrepForRemoting", Type.EmptyTypes, new Expression[0]);
ParameterExpression[] parameterExpressionArray1 = new ParameterExpression[] { parameterExpression1 };
Func<Exception, Exception> func1 = Expression.Lambda<Func<Exception, Exception>>(methodCallExpression2, parameterExpressionArray1).Compile();
func1(new Exception());
func = func1;
}
}
catch
{
}
return (Task task) => {
try
{
task.Wait();
}
catch (AggregateException aggregateException)
{
Exception baseException = aggregateException.GetBaseException();
if (func != null)
{
baseException = func(baseException);
}
throw baseException;
}
};
}
private static void MarkExceptionsObserved(this Task task)
{
AggregateException exception = task.Exception;
}
internal static Task Then(this Task task, Action continuation, CancellationToken cancellationToken = null, bool runSynchronously = false)
{
return task.ThenImpl<Task, TaskHelpersExtensions.AsyncVoid>((Task t) => TaskHelpersExtensions.ToAsyncVoidTask(continuation), cancellationToken, runSynchronously);
}
internal static Task<TOuterResult> Then<TOuterResult>(this Task task, Func<TOuterResult> continuation, CancellationToken cancellationToken = null, bool runSynchronously = false)
{
return task.ThenImpl<Task, TOuterResult>((Task t) => TaskHelpers.FromResult<TOuterResult>(continuation()), cancellationToken, runSynchronously);
}
internal static Task Then(this Task task, Func<Task> continuation, CancellationToken cancellationToken = null, bool runSynchronously = false)
{
Func<TaskHelpersExtensions.AsyncVoid> func = null;
return task.Then<TaskHelpersExtensions.AsyncVoid>(() => {
Task task1 = continuation();
if (func == null)
{
func = () => new TaskHelpersExtensions.AsyncVoid();
}
return task1.Then<TaskHelpersExtensions.AsyncVoid>(func, new CancellationToken(), false);
}, cancellationToken, runSynchronously);
}
internal static Task<TOuterResult> Then<TOuterResult>(this Task task, Func<Task<TOuterResult>> continuation, CancellationToken cancellationToken = null, bool runSynchronously = false)
{
return task.ThenImpl<Task, TOuterResult>((Task t) => continuation(), cancellationToken, runSynchronously);
}
internal static Task Then<TInnerResult>(this Task<TInnerResult> task, Action<TInnerResult> continuation, CancellationToken cancellationToken = null, bool runSynchronously = false)
{
return task.ThenImpl<Task<TInnerResult>, TaskHelpersExtensions.AsyncVoid>((Task<TInnerResult> t) => TaskHelpersExtensions.ToAsyncVoidTask(() => continuation(t.Result)), cancellationToken, runSynchronously);
}
internal static Task<TOuterResult> Then<TInnerResult, TOuterResult>(this Task<TInnerResult> task, Func<TInnerResult, TOuterResult> continuation, CancellationToken cancellationToken = null, bool runSynchronously = false)
{
return task.ThenImpl<Task<TInnerResult>, TOuterResult>((Task<TInnerResult> t) => TaskHelpers.FromResult<TOuterResult>(continuation(t.Result)), cancellationToken, runSynchronously);
}
internal static Task Then<TInnerResult>(this Task<TInnerResult> task, Func<TInnerResult, Task> continuation, CancellationToken token = null, bool runSynchronously = false)
{
return task.ThenImpl<Task<TInnerResult>, TaskHelpersExtensions.AsyncVoid>((Task<TInnerResult> t) => continuation(t.Result).ToTask<TaskHelpersExtensions.AsyncVoid>(new CancellationToken(), new TaskHelpersExtensions.AsyncVoid()), token, runSynchronously);
}
internal static Task<TOuterResult> Then<TInnerResult, TOuterResult>(this Task<TInnerResult> task, Func<TInnerResult, Task<TOuterResult>> continuation, CancellationToken cancellationToken = null, bool runSynchronously = false)
{
return task.ThenImpl<Task<TInnerResult>, TOuterResult>((Task<TInnerResult> t) => continuation(t.Result), cancellationToken, runSynchronously);
}
private static Task<TOuterResult> ThenImpl<TTask, TOuterResult>(this TTask task, Func<TTask, Task<TOuterResult>> continuation, CancellationToken cancellationToken, bool runSynchronously)
where TTask : Task
{
Task<TOuterResult> task1;
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
{
task1 = continuation(task);
}
catch (Exception exception)
{
task1 = TaskHelpers.FromError<TOuterResult>(exception);
}
return task1;
}
}
return TaskHelpersExtensions.ThenImplContinuation<TOuterResult, TTask>(task, continuation, cancellationToken, runSynchronously);
}
private static Task<TOuterResult> ThenImplContinuation<TOuterResult, TTask>(TTask task, Func<TTask, Task<TOuterResult>> continuation, CancellationToken cancellationToken, bool runSynchronously = false)
where TTask : Task
{
SynchronizationContext current = SynchronizationContext.Current;
TaskCompletionSource<Task<TOuterResult>> taskCompletionSource = new TaskCompletionSource<Task<TOuterResult>>();
task.ContinueWith((Task innerTask) => {
if (innerTask.IsFaulted)
{
taskCompletionSource.TrySetException(innerTask.Exception.InnerExceptions);
return;
}
if (innerTask.IsCanceled || cancellationToken.IsCancellationRequested)
{
taskCompletionSource.TrySetCanceled();
return;
}
if (current == null)
{
taskCompletionSource.TrySetResult(continuation(task));
return;
}
current.Post((object state) => {
try
{
taskCompletionSource.TrySetResult(continuation(task));
}
catch (Exception exception)
{
taskCompletionSource.TrySetException(exception);
}
}, null);
}, (runSynchronously ? TaskContinuationOptions.ExecuteSynchronously : TaskContinuationOptions.None));
return taskCompletionSource.Task.FastUnwrap<TOuterResult>();
}
internal static void ThrowIfFaulted(this Task task)
{
TaskHelpersExtensions._rethrowWithNoStackLossDelegate(task);
}
private static Task<TaskHelpersExtensions.AsyncVoid> ToAsyncVoidTask(Action action)
{
return TaskHelpers.RunSynchronously<TaskHelpersExtensions.AsyncVoid>(() => {
action();
return TaskHelpersExtensions._defaultCompleted;
}, new CancellationToken());
}
internal static Task<TResult> ToTask<TResult>(this Task task, CancellationToken cancellationToken = null, TResult result = null)
{
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<TResult>(result);
}
}
return TaskHelpersExtensions.ToTaskContinuation<TResult>(task, result);
}
private static Task<TResult> ToTaskContinuation<TResult>(Task task, TResult result)
{
TaskCompletionSource<TResult> taskCompletionSource = new TaskCompletionSource<TResult>();
task.ContinueWith((Task innerTask) => {
if (task.Status != TaskStatus.RanToCompletion)
{
taskCompletionSource.TrySetFromTask<TResult>(innerTask);
return;
}
taskCompletionSource.TrySetResult(result);
}, TaskContinuationOptions.ExecuteSynchronously);
return taskCompletionSource.Task;
}
internal static bool TryGetResult<TResult>(this Task<TResult> task, out TResult result)
{
if (task.Status != TaskStatus.RanToCompletion)
{
result = default(TResult);
return false;
}
result = task.Result;
return true;
}
private struct AsyncVoid
{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment