Created
July 14, 2014 10:52
-
-
Save micdenny/b5b196917fd24d6798e5 to your computer and use it in GitHub Desktop.
TaskHelpers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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