internal ContinueWithResult(IAsyncOperation op, AsyncContinuationOptions options, object continuation, object userState)
            : base(AsyncOperationStatus.Running)
        {
            _op           = op;
            _options      = options;
            _continuation = continuation;
            _userState    = userState;

            if ((options & AsyncContinuationOptions.ExecuteSynchronously) != 0)
            {
                op.AddCompletionCallback(this, null);
            }
            else
            {
                op.AddCompletionCallback(this);
            }
        }
        public async Task ContinueWth_ExecutesOnAntecedentCancellation(AsyncContinuationOptions options, bool expectedCalled)
        {
            // Arrange
            var op = AsyncResult.FromCanceled();
            var continuationCalled   = false;
            var continuationCanceled = false;
            var continuation         = op.ContinueWith(o => continuationCalled = true, options);

            // Act
            try
            {
                await continuation;
            }
            catch (OperationCanceledException)
            {
                continuationCanceled = true;
            }

            // Assert
            Assert.Equal(expectedCalled, continuationCalled);
            Assert.Equal(!expectedCalled, continuationCanceled);
        }
        /// <summary>
        /// Creates a continuation that executes when the target <see cref="IAsyncOperation"/> completes.
        /// </summary>
        /// <param name="op">The operation to continue.</param>
        /// <param name="action">An action to run when the <paramref name="op"/> completes.</param>
        /// <param name="userState">A user-defined state object that is passed as second argument to <paramref name="action"/>.</param>
        /// <param name="options">Options for when the <paramref name="action"/> is executed.</param>
        /// <exception cref="ArgumentNullException">Thrown if the <paramref name="action"/> is <see langword="null"/>.</exception>
        /// <returns>An operation that is executed after <paramref name="op"/> completes.</returns>
        /// <seealso cref="ContinueWith(IAsyncOperation, Action{IAsyncOperation, object}, object)"/>
        public static IAsyncOperation ContinueWith(this IAsyncOperation op, Action <IAsyncOperation, object> action, object userState, AsyncContinuationOptions options)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            return(new ContinueWithResult <VoidResult, VoidResult>(op, options, action, userState));
        }
        /// <summary>
        /// Creates a continuation that executes when the target <see cref="IAsyncOperation"/> completes.
        /// </summary>
        /// <param name="op">The operation to continue.</param>
        /// <param name="action">An action to run when the <paramref name="op"/> completes.</param>
        /// <param name="userState">A user-defined state object that is passed as second argument to <paramref name="action"/>.</param>
        /// <param name="options">Options for when the <paramref name="action"/> is executed.</param>
        /// <exception cref="ArgumentNullException">Thrown if the <paramref name="action"/> is <see langword="null"/>.</exception>
        /// <returns>An operation that is executed after <paramref name="op"/> completes.</returns>
        /// <seealso cref="ContinueWith{TResult, TNewResult}(IAsyncOperation{TResult}, Func{IAsyncOperation{TResult}, object, TNewResult}, object)"/>
        public static IAsyncOperation <TNewResult> ContinueWith <TResult, TNewResult>(this IAsyncOperation <TResult> op, Func <IAsyncOperation <TResult>, object, TNewResult> action, object userState, AsyncContinuationOptions options)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            return(new ContinueWithResult <TResult, TNewResult>(op, options, action, userState));
        }
        /// <summary>
        /// Creates a continuation that executes when the target <see cref="IAsyncOperation{TResult}"/> completes.
        /// </summary>
        /// <param name="op">The operation to continue.</param>
        /// <param name="action">An action to run when the <paramref name="op"/> completes.</param>
        /// <param name="options">Options for when the <paramref name="action"/> is executed.</param>
        /// <exception cref="ArgumentNullException">Thrown if the <paramref name="action"/> is <see langword="null"/>.</exception>
        /// <returns>An operation that is executed after <paramref name="op"/> completes.</returns>
        /// <seealso cref="ContinueWith{TResult}(IAsyncOperation{TResult}, Action{IAsyncOperation{TResult}})"/>
        public static IAsyncOperation ContinueWith <TResult>(this IAsyncOperation <TResult> op, Action <IAsyncOperation <TResult> > action, AsyncContinuationOptions options)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            return(new ContinueWithResult <TResult, VoidResult>(op, options, action, null));
        }