Exemplo n.º 1
0
        /// <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("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(Helpers.CompletedTask);

            case AsyncStatus.Error:
                return(Helpers.TaskFromException <VoidValueTypeParameter>(source.ErrorCode.AttachRestrictedErrorInfo()));

            case AsyncStatus.Canceled:
                return(Helpers.TaskFromCancellation <VoidValueTypeParameter>(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);
        }
Exemplo n.º 2
0
        /// <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);
        }