/// <summary>Mark the channel as being complete, meaning no more items will be written to it.</summary>
 /// <param name="error">Optional Exception indicating a failure that's causing the channel to complete.</param>
 /// <exception cref="InvalidOperationException">The channel has already been marked as complete.</exception>
 public void Complete(Exception error = null)
 {
     if (!TryComplete(error))
     {
         throw ChannelUtilities.CreateInvalidCompletionException();
     }
 }
        /// <summary>Asynchronously writes an item to the channel.</summary>
        /// <param name="item">The value to write to the channel.</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> used to cancel the write operation.</param>
        /// <returns>A <see cref="Task"/> that represents the asynchronous write operation.</returns>
        public virtual Task WriteAsync(T item, CancellationToken cancellationToken = default(CancellationToken))
        {
            try
            {
                return
                    (cancellationToken.IsCancellationRequested ? Task.FromCanceled <T>(cancellationToken) :
                     TryWrite(item) ? Task.CompletedTask :
                     WriteAsyncCore(item, cancellationToken));
            }
            catch (Exception e)
            {
                return(Task.FromException(e));
            }

            async Task WriteAsyncCore(T innerItem, CancellationToken ct)
            {
                while (await WaitToWriteAsync(ct).ConfigureAwait(false))
                {
                    if (TryWrite(innerItem))
                    {
                        return;
                    }
                }

                throw ChannelUtilities.CreateInvalidCompletionException();
            }
        }