public static Task AsTask <TProgress>(this IAsyncActionWithProgress <TProgress> source, CancellationToken cancellationToken, IProgress <TProgress> progress) { if (source == null) { throw new ArgumentNullException(nameof(source)); } // TODO: Handle the scenario where the 'IAsyncActionWithProgress' is actually a task (i.e. originated from native code // but projected into an IAsyncActionWithProgress) switch (source.Status) { case AsyncStatus.Completed: return(Task.CompletedTask); case AsyncStatus.Error: return(Task.FromException(source.ErrorCode)); case AsyncStatus.Canceled: return(Task.FromCanceled(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true))); } if (progress != null) { SetProgress(source, progress); } var bridge = new AsyncInfoToTaskBridge <VoidValueTypeParameter, TProgress>(cancellationToken); source.Completed = new AsyncActionWithProgressCompletedHandler <TProgress>(bridge.CompleteFromAsyncActionWithProgress); bridge.RegisterForCancellation(source); return(bridge.Task); }
public static Task <TResult> AsTask <TResult>(this IAsyncOperation <TResult> source, CancellationToken cancellationToken) { if (source == null) { throw new ArgumentNullException(nameof(source)); } // TODO: Handle the scenario where the 'IAsyncOperation' is actually a task (i.e. originated from native code // but projected into an IAsyncOperation) switch (source.Status) { case AsyncStatus.Completed: return(Task.FromResult(source.GetResults())); case AsyncStatus.Error: return(Task.FromException <TResult>(source.ErrorCode)); case AsyncStatus.Canceled: return(Task.FromCanceled <TResult>(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true))); } var bridge = new AsyncInfoToTaskBridge <TResult, VoidValueTypeParameter>(cancellationToken); source.Completed = new AsyncOperationCompletedHandler <TResult>(bridge.CompleteFromAsyncOperation); bridge.RegisterForCancellation(source); return(bridge.Task); }
/// <summary>Gets a Task to represent the asynchronous operation.</summary> /// <param name="source">The asynchronous operation.</param> /// <param name="cancellationToken">The token used to request cancellation of the asynchronous operation.</param> /// <returns>The Task representing the asynchronous operation.</returns> public static Task AsTask(this IAsyncAction source, CancellationToken cancellationToken) { if (source == null) { throw new ArgumentNullException(nameof(source)); } Contract.EndContractBlock(); // If source is actually a NetFx-to-WinRT adapter, unwrap it instead of creating a new Task: var wrapper = source as TaskToAsyncActionAdapter; if (wrapper != null && !wrapper.CompletedSynchronously) { Task innerTask = wrapper.Task; Debug.Assert(innerTask != null); Debug.Assert(innerTask.Status != TaskStatus.Created); if (!innerTask.IsCompleted) { // The race here is benign: If the task completes here, the concatination is useless, but not damaging. if (cancellationToken.CanBeCanceled && wrapper.CancelTokenSource != null) { ConcatenateCancelTokens(cancellationToken, wrapper.CancelTokenSource, innerTask); } } return(innerTask); } // Fast path to return a completed Task if the operation has already completed: switch (source.Status) { case AsyncStatus.Completed: return(Task.CompletedTask); case AsyncStatus.Error: return(Task.FromException(source.ErrorCode.AttachRestrictedErrorInfo())); case AsyncStatus.Canceled: return(Task.FromCanceled(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true))); } // Benign race: source may complete here. Things still work, just not taking the fast path. // Source is not a NetFx-to-WinRT adapter, but a native future. Hook up the task: var bridge = new AsyncInfoToTaskBridge <VoidValueTypeParameter>(cancellationToken); try { source.Completed = new AsyncActionCompletedHandler(bridge.CompleteFromAsyncAction); bridge.RegisterForCancellation(source); } catch { AsyncCausalitySupport.RemoveFromActiveTasks(bridge.Task); } return(bridge.Task); }
/// <summary>Gets a Task to represent the asynchronous operation.</summary> /// <param name="source">The asynchronous operation.</param> /// <param name="cancellationToken">The token used to request cancellation of the asynchronous operation.</param> /// <param name="progress">The progress object used to receive progress updates.</param> /// <returns>The Task representing the asynchronous operation.</returns> public static Task <TResult> AsTask <TResult, TProgress>(this IAsyncOperationWithProgress <TResult, TProgress> source, CancellationToken cancellationToken, IProgress <TProgress> progress) { if (source == null) { throw new ArgumentNullException("source"); } Contract.EndContractBlock(); // If source is actually a NetFx-to-WinRT adapter, unwrap it instead of creating a new Task: var wrapper = source as TaskToAsyncOperationWithProgressAdapter <TResult, TProgress>; if (wrapper != null && !wrapper.CompletedSynchronously) { Task <TResult> innerTask = wrapper.Task as Task <TResult>; Debug.Assert(innerTask != null); Debug.Assert(innerTask.Status != TaskStatus.Created); // Is WaitingForActivation a legal state at this moment? if (!innerTask.IsCompleted) { // The race here is benign: If the task completes here, the concatinations are useless, but not damaging. if (cancellationToken.CanBeCanceled && wrapper.CancelTokenSource != null) { ConcatenateCancelTokens(cancellationToken, wrapper.CancelTokenSource, innerTask); } if (progress != null) { ConcatenateProgress(source, progress); } } return(innerTask); } // Fast path to return a completed Task if the operation has already completed switch (source.Status) { case AsyncStatus.Completed: return(Task.FromResult(source.GetResults())); case AsyncStatus.Error: return(Task.FromException <TResult>(RestrictedErrorInfoHelper.AttachRestrictedErrorInfo(source.ErrorCode))); case AsyncStatus.Canceled: return(Task.FromCancellation <TResult>(cancellationToken.IsCancellationRequested ? cancellationToken : new CancellationToken(true))); } // Benign race: source may complete here. Things still work, just not taking the fast path. // Forward progress reports: if (progress != null) { ConcatenateProgress(source, progress); } // Source is not a NetFx-to-WinRT adapter, but a native future. Hook up the task: var bridge = new AsyncInfoToTaskBridge <TResult, TProgress>(cancellationToken); source.Completed = new AsyncOperationWithProgressCompletedHandler <TResult, TProgress>(bridge.CompleteFromAsyncOperationWithProgress); bridge.RegisterForCancellation(source); return(bridge.Task); }