public static ReadOnlyCollectionPage <T> GetNextPage <T>(this ReadOnlyCollectionPage <T> page)
        {
            if (page == null)
            {
                throw new ArgumentNullException("page");
            }

            try
            {
                return(page.GetNextPageAsync(CancellationToken.None).Result);
            }
            catch (AggregateException ex)
            {
                ReadOnlyCollection <Exception> innerExceptions = ex.Flatten().InnerExceptions;
                if (innerExceptions.Count == 1)
                {
                    throw innerExceptions[0];
                }

                throw;
            }
        }
コード例 #2
0
        /// <summary>
        /// Get all pages in a paginated collection.
        /// </summary>
        /// <remarks>
        /// If <paramref name="progress"/> is non-<see langword="null"/>, the first call to
        /// <see cref="IProgress{T}.Report"/> will specify the <paramref name="page"/>
        /// argument. After each task to obtain to the next page of results completes,
        /// the <see cref="IProgress{T}.Report"/> method will be called again with the
        /// new page of results.
        /// <para>
        /// This method determines that the end of the collection is reached when either of
        /// the following conditions is true.
        /// </para>
        /// <list type="bullet">
        /// <item>The <see cref="ReadOnlyCollectionPage{T}.CanHaveNextPage"/> property returns <see langword="false"/>.</item>
        /// <item>An empty page is reached.</item>
        /// </list>
        /// </remarks>
        /// <typeparam name="T">The type of elements in the collection.</typeparam>
        /// <param name="page">The first page in the collection.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param>
        /// <param name="progress">An optional callback object to receive progress notifications. If this is <see langword="null"/>, no progress notifications are sent.</param>
        /// <returns>
        /// A <see cref="Task"/> object representing the asynchronous operation. When the operation
        /// completes successfully, the <see cref="Task{TResult}.Result"/> property will contain a
        /// read-only collection containing the complete set of results from the paginated collection.
        /// </returns>
        /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <see langword="null"/>.</exception>
        public static Task <ReadOnlyCollection <T> > GetAllPagesAsync <T>(this ReadOnlyCollectionPage <T> page, CancellationToken cancellationToken, IProgress <ReadOnlyCollectionPage <T> > progress)
        {
            if (page == null)
            {
                throw new ArgumentNullException("page");
            }

            if (progress != null)
            {
                progress.Report(page);
            }

            if (!page.CanHaveNextPage || page.Count == 0)
            {
                return(InternalTaskExtensions.CompletedTask <ReadOnlyCollection <T> >(page));
            }

            TaskCompletionSource <ReadOnlyCollection <T> > taskCompletionSource = new TaskCompletionSource <ReadOnlyCollection <T> >();

            List <T> result = new List <T>(page);
            ReadOnlyCollectionPage <T> currentPage = page;
            Func <Task <ReadOnlyCollectionPage <T> > >   getNextPage  = () => currentPage.GetNextPageAsync(cancellationToken);
            Task <ReadOnlyCollectionPage <T> >           currentTask  = getNextPage();
            Action <Task <ReadOnlyCollectionPage <T> > > continuation = null;

            continuation =
                previousTask =>
            {
                if (previousTask.Status != TaskStatus.RanToCompletion)
                {
                    taskCompletionSource.SetFromTask(previousTask);
                    return;
                }

                currentPage = previousTask.Result;
                if (currentPage == null)
                {
                    // TODO: should we throw an exception instead?
                    taskCompletionSource.SetResult(result.AsReadOnly());
                    return;
                }

                if (progress != null)
                {
                    progress.Report(currentPage);
                }

                result.AddRange(currentPage);
                if (!currentPage.CanHaveNextPage || currentPage.Count == 0)
                {
                    taskCompletionSource.SetResult(result.AsReadOnly());
                    return;
                }

                // continue with the next page
                currentTask = getNextPage();
                // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks
                currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);
            };
            // use ContinueWith since the continuation handles cancellation and faulted antecedent tasks
            currentTask.ContinueWith(continuation, TaskContinuationOptions.ExecuteSynchronously);


            return(taskCompletionSource.Task);
        }