|
|
|
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace Microsoft.AspNet.SignalR
|
|
|
|
|
{
|
|
|
|
|
internal static class TaskAsyncHelper
|
|
|
|
|
{
|
|
|
|
|
private static readonly Task _emptyTask = MakeTask<object>(null);
|
|
|
|
|
private static readonly Task<bool> _trueTask = MakeTask<bool>(true);
|
|
|
|
|
private static readonly Task<bool> _falseTask = MakeTask<bool>(false);
|
|
|
|
|
|
|
|
|
|
private static Task<T> MakeTask<T>(T value)
|
|
|
|
|
{
|
|
|
|
|
return FromResult<T>(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Empty
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _emptyTask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<bool> True
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _trueTask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<bool> False
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return _falseTask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task OrEmpty(this Task task)
|
|
|
|
|
{
|
|
|
|
|
return task ?? Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<T> OrEmpty<T>(this Task<T> task)
|
|
|
|
|
{
|
|
|
|
|
return task ?? TaskCache<T>.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task FromAsync(Func<AsyncCallback, object, IAsyncResult> beginMethod, Action<IAsyncResult> endMethod, object state)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return Task.Factory.FromAsync(beginMethod, endMethod, state);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return TaskAsyncHelper.FromError(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task<T> FromAsync<T>(Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, T> endMethod, object state)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return Task.Factory.FromAsync<T>(beginMethod, endMethod, state);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return TaskAsyncHelper.FromError<T>(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Series(Func<object, Task>[] tasks, object[] state)
|
|
|
|
|
{
|
|
|
|
|
Task prev = TaskAsyncHelper.Empty;
|
|
|
|
|
Task finalTask = TaskAsyncHelper.Empty;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < tasks.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
prev = finalTask;
|
|
|
|
|
finalTask = prev.Then(tasks[i], state[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return finalTask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static TTask Catch<TTask>(this TTask task) where TTask : Task
|
|
|
|
|
{
|
|
|
|
|
return Catch(task, ex => { });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if PERFCOUNTERS
|
|
|
|
|
public static TTask Catch<TTask>(this TTask task, params IPerformanceCounter[] counters) where TTask : Task
|
|
|
|
|
{
|
|
|
|
|
return Catch(task, _ =>
|
|
|
|
|
{
|
|
|
|
|
if (counters == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (var i = 0; i < counters.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
counters[i].Increment();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static TTask Catch<TTask>(this TTask task, Action<AggregateException, object> handler, object state) where TTask : Task
|
|
|
|
|
{
|
|
|
|
|
if (task != null && task.Status != TaskStatus.RanToCompletion)
|
|
|
|
|
{
|
|
|
|
|
if (task.Status == TaskStatus.Faulted)
|
|
|
|
|
{
|
|
|
|
|
ExecuteOnFaulted(handler, state, task.Exception);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
AttachFaultedContinuation<TTask>(task, handler, state);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
private static void AttachFaultedContinuation<TTask>(TTask task, Action<AggregateException, object> handler, object state) where TTask : Task
|
|
|
|
|
{
|
|
|
|
|
task.ContinueWith(innerTask =>
|
|
|
|
|
{
|
|
|
|
|
ExecuteOnFaulted(handler, state, innerTask.Exception);
|
|
|
|
|
},
|
|
|
|
|
TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
private static void ExecuteOnFaulted(Action<AggregateException, object> handler, object state, AggregateException exception)
|
|
|
|
|
{
|
|
|
|
|
// observe Exception
|
|
|
|
|
#if !WINDOWS_PHONE && !SILVERLIGHT && !NETFX_CORE
|
|
|
|
|
Trace.TraceError("SignalR exception thrown by Task: {0}", exception);
|
|
|
|
|
#endif
|
|
|
|
|
handler(exception, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static TTask Catch<TTask>(this TTask task, Action<AggregateException> handler) where TTask : Task
|
|
|
|
|
{
|
|
|
|
|
return task.Catch((ex, state) => ((Action<AggregateException>)state).Invoke(ex),
|
|
|
|
|
handler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task ContinueWithNotComplete(this Task task, Action action)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
action();
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
return FromError(e);
|
|
|
|
|
}
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return task;
|
|
|
|
|
default:
|
|
|
|
|
var tcs = new TaskCompletionSource<object>();
|
|
|
|
|
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
if (t.IsFaulted || t.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
action();
|
|
|
|
|
|
|
|
|
|
if (t.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetCanceled();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetException(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetResult(null);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
TaskContinuationOptions.ExecuteSynchronously);
|
|
|
|
|
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static void ContinueWithNotComplete(this Task task, TaskCompletionSource<object> tcs)
|
|
|
|
|
{
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
if (t.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else if (t.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
TaskContinuationOptions.NotOnRanToCompletion);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static void ContinueWith(this Task task, TaskCompletionSource<object> tcs)
|
|
|
|
|
{
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
if (t.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else if (t.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetCanceled();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetResult(null);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
TaskContinuationOptions.ExecuteSynchronously);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static void ContinueWith<T>(this Task<T> task, TaskCompletionSource<T> tcs)
|
|
|
|
|
{
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
if (t.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else if (t.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetCanceled();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tcs.TrySetResult(t.Result);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Return(this Task[] tasks)
|
|
|
|
|
{
|
|
|
|
|
return Then(tasks, () => { });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Then extesions
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then(this Task task, Action successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return RunTask(task, successor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<TResult> Then<TResult>(this Task task, Func<TResult> successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
return FromError<TResult>(task.Exception);
|
|
|
|
|
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return Canceled<TResult>();
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return TaskRunners<object, TResult>.RunTask(task, successor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then(this Task[] tasks, Action successor)
|
|
|
|
|
{
|
|
|
|
|
if (tasks.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
return FromMethod(successor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var tcs = new TaskCompletionSource<object>();
|
|
|
|
|
Task.Factory.ContinueWhenAll(tasks, completedTasks =>
|
|
|
|
|
{
|
|
|
|
|
var faulted = completedTasks.FirstOrDefault(t => t.IsFaulted);
|
|
|
|
|
if (faulted != null)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(faulted.Exception);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var cancelled = completedTasks.FirstOrDefault(t => t.IsCanceled);
|
|
|
|
|
if (cancelled != null)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
successor();
|
|
|
|
|
tcs.SetResult(null);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then<T1>(this Task task, Action<T1> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, arg1);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return GenericDelegates<object, object, T1, object>.ThenWithArgs(task, successor, arg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then<T1, T2>(this Task task, Action<T1, T2> successor, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, arg1, arg2);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return GenericDelegates<object, object, T1, T2>.ThenWithArgs(task, successor, arg1, arg2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then<T1>(this Task task, Func<T1, Task> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, arg1);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return GenericDelegates<object, Task, T1, object>.ThenWithArgs(task, successor, arg1)
|
|
|
|
|
.FastUnwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then<T1, T2>(this Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, arg1, arg2);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return GenericDelegates<object, Task, T1, T2>.ThenWithArgs(task, successor, arg1, arg2)
|
|
|
|
|
.FastUnwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, Task<TResult>> successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
return FromError<TResult>(task.Exception);
|
|
|
|
|
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return Canceled<TResult>();
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, task.Result);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result))
|
|
|
|
|
.FastUnwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, TResult> successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
return FromError<TResult>(task.Exception);
|
|
|
|
|
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return Canceled<TResult>();
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, task.Result);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<TResult> Then<T, T1, TResult>(this Task<T> task, Func<T, T1, TResult> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
return FromError<TResult>(task.Exception);
|
|
|
|
|
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return Canceled<TResult>();
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, task.Result, arg1);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return GenericDelegates<T, TResult, T1, object>.ThenWithArgs(task, successor, arg1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then(this Task task, Func<Task> successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return TaskRunners<object, Task>.RunTask(task, successor)
|
|
|
|
|
.FastUnwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<TResult> Then<TResult>(this Task task, Func<Task<TResult>> successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
return FromError<TResult>(task.Exception);
|
|
|
|
|
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return Canceled<TResult>();
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return TaskRunners<object, Task<TResult>>.RunTask(task, successor)
|
|
|
|
|
.FastUnwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then<TResult>(this Task<TResult> task, Action<TResult> successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, task.Result);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return TaskRunners<TResult, object>.RunTask(task, successor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Then<TResult>(this Task<TResult> task, Func<TResult, Task> successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, task.Result);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return TaskRunners<TResult, Task>.RunTask(task, t => successor(t.Result))
|
|
|
|
|
.FastUnwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<TResult> Then<TResult, T1>(this Task<TResult> task, Func<Task<TResult>, T1, Task<TResult>> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor, task, arg1);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return GenericDelegates<TResult, Task<TResult>, T1, object>.ThenWithArgs(task, successor, arg1)
|
|
|
|
|
.FastUnwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are flowed to the caller")]
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Finally(this Task task, Action<object> next, object state)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
next(state);
|
|
|
|
|
return task;
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(next, state);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return RunTaskSynchronously(task, next, state, onlyOnSuccess: false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task RunSynchronously(this Task task, Action successor)
|
|
|
|
|
{
|
|
|
|
|
switch (task.Status)
|
|
|
|
|
{
|
|
|
|
|
case TaskStatus.Faulted:
|
|
|
|
|
case TaskStatus.Canceled:
|
|
|
|
|
return task;
|
|
|
|
|
|
|
|
|
|
case TaskStatus.RanToCompletion:
|
|
|
|
|
return FromMethod(successor);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return RunTaskSynchronously(task, state => ((Action)state).Invoke(), successor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task FastUnwrap(this Task<Task> task)
|
|
|
|
|
{
|
|
|
|
|
var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null;
|
|
|
|
|
return innerTask ?? task.Unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<T> FastUnwrap<T>(this Task<Task<T>> task)
|
|
|
|
|
{
|
|
|
|
|
var innerTask = (task.Status == TaskStatus.RanToCompletion) ? task.Result : null;
|
|
|
|
|
return innerTask ?? task.Unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task Delay(TimeSpan timeOut)
|
|
|
|
|
{
|
|
|
|
|
#if NETFX_CORE
|
|
|
|
|
return Task.Delay(timeOut);
|
|
|
|
|
#else
|
|
|
|
|
var tcs = new TaskCompletionSource<object>();
|
|
|
|
|
|
|
|
|
|
var timer = new Timer(tcs.SetResult,
|
|
|
|
|
null,
|
|
|
|
|
timeOut,
|
|
|
|
|
TimeSpan.FromMilliseconds(-1));
|
|
|
|
|
|
|
|
|
|
return tcs.Task.ContinueWith(_ =>
|
|
|
|
|
{
|
|
|
|
|
timer.Dispose();
|
|
|
|
|
},
|
|
|
|
|
TaskContinuationOptions.ExecuteSynchronously);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task FromMethod(Action func)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
func();
|
|
|
|
|
return Empty;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task FromMethod<T1>(Action<T1> func, T1 arg)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
func(arg);
|
|
|
|
|
return Empty;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task FromMethod<T1, T2>(Action<T1, T2> func, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
func(arg1, arg2);
|
|
|
|
|
return Empty;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task FromMethod(Func<Task> func)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return func();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task<TResult> FromMethod<TResult>(Func<Task<TResult>> func)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return func();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError<TResult>(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task<TResult> FromMethod<TResult>(Func<TResult> func)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return FromResult<TResult>(func());
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError<TResult>(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task FromMethod<T1>(Func<T1, Task> func, T1 arg)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return func(arg);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task FromMethod<T1, T2>(Func<T1, T2, Task> func, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return func(arg1, arg2);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task<TResult> FromMethod<T1, TResult>(Func<T1, Task<TResult>> func, T1 arg)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return func(arg);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError<TResult>(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task<TResult> FromMethod<T1, TResult>(Func<T1, TResult> func, T1 arg)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return FromResult<TResult>(func(arg));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError<TResult>(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task<TResult> FromMethod<T1, T2, TResult>(Func<T1, T2, Task<TResult>> func, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return func(arg1, arg2);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError<TResult>(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
public static Task<TResult> FromMethod<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return FromResult<TResult>(func(arg1, arg2));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
return FromError<TResult>(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
public static Task<T> FromResult<T>(T value)
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<T>();
|
|
|
|
|
tcs.SetResult(value);
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
internal static Task FromError(Exception e)
|
|
|
|
|
{
|
|
|
|
|
return FromError<object>(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
internal static Task<T> FromError<T>(Exception e)
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<T>();
|
|
|
|
|
tcs.SetUnwrappedException<T>(e);
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
internal static void SetUnwrappedException<T>(this TaskCompletionSource<T> tcs, Exception e)
|
|
|
|
|
{
|
|
|
|
|
var aggregateException = e as AggregateException;
|
|
|
|
|
if (aggregateException != null)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetException(aggregateException.InnerExceptions);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tcs.SetException(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
internal static bool TrySetUnwrappedException<T>(this TaskCompletionSource<T> tcs, Exception e)
|
|
|
|
|
{
|
|
|
|
|
var aggregateException = e as AggregateException;
|
|
|
|
|
if (aggregateException != null)
|
|
|
|
|
{
|
|
|
|
|
return tcs.TrySetException(aggregateException.InnerExceptions);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return tcs.TrySetException(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
private static Task Canceled()
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<object>();
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
private static Task<T> Canceled<T>()
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<T>();
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
private static Task RunTask(Task task, Action successor)
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<object>();
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
if (t.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else if (t.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
successor();
|
|
|
|
|
tcs.SetResult(null);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This is a shared file")]
|
|
|
|
|
private static Task RunTaskSynchronously(Task task, Action<object> next, object state, bool onlyOnSuccess = true)
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<object>();
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (t.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
if (!onlyOnSuccess)
|
|
|
|
|
{
|
|
|
|
|
next(state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tcs.SetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else if (t.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
if (!onlyOnSuccess)
|
|
|
|
|
{
|
|
|
|
|
next(state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
next(state);
|
|
|
|
|
tcs.SetResult(null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(ex);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
TaskContinuationOptions.ExecuteSynchronously);
|
|
|
|
|
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class TaskRunners<T, TResult>
|
|
|
|
|
{
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
internal static Task RunTask(Task<T> task, Action<T> successor)
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<object>();
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
if (t.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else if (t.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
successor(t.Result);
|
|
|
|
|
tcs.SetResult(null);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
internal static Task<TResult> RunTask(Task task, Func<TResult> successor)
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<TResult>();
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
if (t.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else if (t.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
tcs.SetResult(successor());
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exceptions are set in a tcs")]
|
|
|
|
|
internal static Task<TResult> RunTask(Task<T> task, Func<Task<T>, TResult> successor)
|
|
|
|
|
{
|
|
|
|
|
var tcs = new TaskCompletionSource<TResult>();
|
|
|
|
|
task.ContinueWith(t =>
|
|
|
|
|
{
|
|
|
|
|
if (task.IsFaulted)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(t.Exception);
|
|
|
|
|
}
|
|
|
|
|
else if (task.IsCanceled)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetCanceled();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
tcs.SetResult(successor(t));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
tcs.SetUnwrappedException(ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return tcs.Task;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class GenericDelegates<T, TResult, T1, T2>
|
|
|
|
|
{
|
|
|
|
|
internal static Task ThenWithArgs(Task task, Action<T1> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
return RunTask(task, () => successor(arg1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task ThenWithArgs(Task task, Action<T1, T2> successor, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
return RunTask(task, () => successor(arg1, arg2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task<TResult> ThenWithArgs(Task task, Func<T1, TResult> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task<TResult> ThenWithArgs(Task task, Func<T1, T2, TResult> successor, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
return TaskRunners<object, TResult>.RunTask(task, () => successor(arg1, arg2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task<TResult> ThenWithArgs(Task<T> task, Func<T, T1, TResult> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
return TaskRunners<T, TResult>.RunTask(task, t => successor(t.Result, arg1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task<Task> ThenWithArgs(Task task, Func<T1, Task> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
return TaskRunners<object, Task>.RunTask(task, () => successor(arg1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task<Task> ThenWithArgs(Task task, Func<T1, T2, Task> successor, T1 arg1, T2 arg2)
|
|
|
|
|
{
|
|
|
|
|
return TaskRunners<object, Task>.RunTask(task, () => successor(arg1, arg2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task<Task<TResult>> ThenWithArgs(Task<T> task, Func<T, T1, Task<TResult>> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
return TaskRunners<T, Task<TResult>>.RunTask(task, t => successor(t.Result, arg1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static Task<Task<T>> ThenWithArgs(Task<T> task, Func<Task<T>, T1, Task<T>> successor, T1 arg1)
|
|
|
|
|
{
|
|
|
|
|
return TaskRunners<T, Task<T>>.RunTask(task, t => successor(t, arg1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class TaskCache<T>
|
|
|
|
|
{
|
|
|
|
|
public static Task<T> Empty = MakeTask<T>(default(T));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|