/// <summary>
        /// Provides support for a conditional "while" loop in asynchronous code, without requiring the use of <see langword="async/await"/>.
        /// </summary>
        /// <remarks>
        /// This code implements support for the following construct without requiring the use of <see langword="async/await"/>.
        ///
        /// <code language="cs">
        /// while (await condition().ConfigureAwait(false))
        /// {
        ///     await body().ConfigureAwait(false);
        /// }
        /// </code>
        /// </remarks>
        /// <param name="condition">A function which returns a <see cref="Task"/> representing the asynchronous evaluation of the <c>while</c> condition.</param>
        /// <param name="body">A function which returns a <see cref="Task"/> representing one iteration of the body of the <c>while</c> loop.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        /// <example>
        /// The following example shows a basic "while" loop implemented using this building block.
        /// <code source="..\Samples\CSharpSamples\TaskBlockWhileAsyncCondition.cs" region="WhileAsyncBuildingBlock" language="cs"/>
        /// <para>
        /// For reference, the following example demonstrates a (nearly) equivalent implementation of this behavior using
        /// the <see langword="async/await"/> operators.
        /// </para>
        /// <code source="..\Samples\CSharpSamples\TaskBlockWhileAsyncCondition.cs" region="WhileAsyncAwait" language="cs"/>
        /// </example>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="condition"/> is <see langword="null"/>.
        /// <para>-or-</para>
        /// <para>If <paramref name="body"/> is <see langword="null"/>.</para>
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If <paramref name="condition"/> returns <see langword="null"/>.
        /// <para>-or-</para>
        /// <para>If <paramref name="body"/> returns <see langword="null"/>.</para>
        /// </exception>
        public static Task While(Func <Task <bool> > condition, Func <Task> body)
        {
            if (condition == null)
            {
                throw new ArgumentNullException("condition");
            }
            if (body == null)
            {
                throw new ArgumentNullException("body");
            }

            TaskCompletionSource <VoidResult> taskCompletionSource = new TaskCompletionSource <VoidResult>();
            Task currentTask;

            Action <Task> statusCheck =
                previousTask =>
            {
                if (previousTask.Status != TaskStatus.RanToCompletion)
                {
                    taskCompletionSource.SetFromFailedTask(previousTask);
                }
            };

            Func <Task, Task <bool> > conditionContinuation =
                previousTask =>
            {
                Task <bool> conditionTask = condition();
                if (conditionTask == null)
                {
                    throw new InvalidOperationException("The Task provided by the 'condition' delegate cannot be null.");
                }

                return(conditionTask);
            };

            Action <Task <bool> > continuation = null;

            continuation =
                previousTask =>
            {
                if (!previousTask.Result)
                {
                    taskCompletionSource.TrySetResult(default(VoidResult));
                    return;
                }

                // reschedule
                Task bodyTask = body();
                if (bodyTask == null)
                {
                    throw new InvalidOperationException("The Task provided by the 'body' delegate cannot be null.");
                }

                currentTask = bodyTask.Then(conditionContinuation).Select(continuation).Finally(statusCheck);
            };

            currentTask = CompletedTask.Default.Then(conditionContinuation).Select(continuation).Finally(statusCheck);
            return(taskCompletionSource.Task);
        }
        /// <summary>
        /// Provides support for a conditional "while" loop in asynchronous code, without requiring the use of <see langword="async/await"/>.
        /// </summary>
        /// <remarks>
        /// This code implements support for the following construct without requiring the use of <see langword="async/await"/>.
        ///
        /// <code language="cs">
        /// while (condition())
        /// {
        ///     await body().ConfigureAwait(false);
        /// }
        /// </code>
        /// </remarks>
        /// <param name="condition">A function which evaluates the condition of the asynchronous <c>while</c> loop.</param>
        /// <param name="body">A function which returns a <see cref="Task"/> representing one iteration of the body of the <c>while</c> loop.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        /// <example>
        /// The following example shows a basic "while" loop implemented using this building block.
        /// <code source="..\Samples\CSharpSamples\TaskBlockWhileAsync.cs" region="WhileAsyncBuildingBlock" language="cs"/>
        /// <para>
        /// For reference, the following example demonstrates a (nearly) equivalent implementation of this behavior using
        /// the <see langword="async/await"/> operators.
        /// </para>
        /// <code source="..\Samples\CSharpSamples\TaskBlockWhileAsync.cs" region="WhileAsyncAwait" language="cs"/>
        /// </example>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="condition"/> is <see langword="null"/>.
        /// <para>-or-</para>
        /// <para>If <paramref name="body"/> is <see langword="null"/>.</para>
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If <paramref name="body"/> returns <see langword="null"/>.
        /// </exception>
        public static Task While(Func <bool> condition, Func <Task> body)
        {
            if (condition == null)
            {
                throw new ArgumentNullException("condition");
            }
            if (body == null)
            {
                throw new ArgumentNullException("body");
            }

            TaskCompletionSource <VoidResult> taskCompletionSource = new TaskCompletionSource <VoidResult>();
            Task currentTask;

            // This action specifically handles cases where evaluating condition or body
            // results in an exception.
            Action <Task> handleErrors =
                previousTask =>
            {
                if (previousTask.Status != TaskStatus.RanToCompletion)
                {
                    taskCompletionSource.SetFromFailedTask(previousTask);
                }
            };

            Action <Task> continuation = null;

            continuation =
                previousTask =>
            {
                if (!condition())
                {
                    taskCompletionSource.SetResult(default(VoidResult));
                    return;
                }

                // reschedule
                Task bodyTask = body();
                if (bodyTask == null)
                {
                    throw new InvalidOperationException("The Task provided by the 'body' delegate cannot be null.");
                }

                currentTask = bodyTask.Select(continuation).Finally(handleErrors);
            };

            currentTask = CompletedTask.Default.Select(continuation).Finally(handleErrors);
            return(taskCompletionSource.Task);
        }