/// <summary>
        /// Called when the dialog is started and pushed onto the dialog stack.
        /// </summary>
        /// <param name="dc">The <see cref="DialogContext"/> for the current turn of conversation.</param>
        /// <param name="options">Optional, initial information to pass to the dialog.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            if (Disabled != null && Disabled.GetValue(dc.State))
            {
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }

            var changeType = ChangeType.GetValue(dc.State);

            if (this.ItemsProperty == null)
            {
                throw new InvalidOperationException($"EditArray: \"{changeType}\" operation couldn't be performed because the {nameof(ItemsProperty)} wasn't specified.");
            }

            var property = this.ItemsProperty.GetValue(dc.State);
            var array    = dc.State.GetValue <JArray>(property, () => new JArray());

            object item   = null;
            object result = null;

            switch (changeType)
            {
            case ArrayChangeType.Pop:
                item = array[array.Count - 1];
                array.RemoveAt(array.Count - 1);
                result = item;
                break;

            case ArrayChangeType.Push:
                EnsureValue();
                var(itemResult, error) = this.Value.TryGetValue(dc.State);
                if (error == null && itemResult != null)
                {
                    array.Add(itemResult);
                }

                break;

            case ArrayChangeType.Take:
                if (array.Count == 0)
                {
                    break;
                }

                item = array[0];
                array.RemoveAt(0);
                result = item;
                break;

            case ArrayChangeType.Remove:
                EnsureValue();
                (itemResult, error) = this.Value.TryGetValue(dc.State);
                if (error == null && itemResult != null)
                {
                    result = false;
                    for (var i = 0; i < array.Count; ++i)
                    {
                        if (array[i].ToString() == itemResult.ToString() || JToken.DeepEquals(array[i], JToken.FromObject(itemResult)))
                        {
                            result = true;
                            array.RemoveAt(i);
                            break;
                        }
                    }
                }

                break;

            case ArrayChangeType.Clear:
                result = array.Count > 0;
                array.Clear();
                break;
            }

            dc.State.SetValue(property, array);

            if (ResultProperty != null)
            {
                dc.State.SetValue(this.ResultProperty.GetValue(dc.State), result);
            }

            return(await dc.EndDialogAsync(result, cancellationToken).ConfigureAwait(false));
        }