/// <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(Helpers.TaskFromException <TResult>(source.ErrorCode.AttachRestrictedErrorInfo())); case AsyncStatus.Canceled: return(Helpers.TaskFromCancellation <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>(cancellationToken); try { source.Completed = new AsyncOperationWithProgressCompletedHandler <TResult, TProgress>(bridge.CompleteFromAsyncOperationWithProgress); bridge.RegisterForCancellation(source); } catch { AsyncCausalitySupport.RemoveFromActiveTasks(bridge.Task); } return(bridge.Task); }