コード例 #1
0
        private void AddSubcommandImpl <TSubCommand>(ConventionContext context, SubcommandAttribute subcommand)
            where TSubCommand : class
        {
#pragma warning disable 618
            context.Application.Command <TSubCommand>(subcommand.Name !, subcommand.Configure);
#pragma warning restore 618
        }
コード例 #2
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            var modelAccessor = context.ModelAccessor;

            if (context.ModelType == null || modelAccessor == null)
            {
                return;
            }

            const BindingFlags MethodFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

            var method = context.ModelType
                         .GetTypeInfo()
                         .GetMethod("OnValidationError", MethodFlags);

            if (method == null)
            {
                return;
            }

            context.Application.ValidationErrorHandler = (v) =>
            {
                var arguments = ReflectionHelper.BindParameters(method, context.Application, default);
                var result    = method.Invoke(modelAccessor.GetModel(), arguments);
                if (method.ReturnType == typeof(int))
                {
                    return((int)result);
                }

                return(CommandLineApplication.ValidationErrorExitCode);
            };
        }
コード例 #3
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            var subcommandProp = context.ModelType.GetTypeInfo().GetProperty("Subcommand", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            if (subcommandProp == null)
            {
                return;
            }

            var setter = ReflectionHelper.GetPropertySetter(subcommandProp);

            context.Application.OnParsed(r =>
            {
                var subCommand = r.SelectedCommand;
                while (subCommand != null)
                {
                    if (ReferenceEquals(subCommand.Parent, context.Application))
                    {
                        if (subCommand is IModelAccessor subcmdAccessor)
                        {
                            setter(context.ModelAccessor.GetModel(), subcmdAccessor.GetModel());
                        }
                        return;
                    }
                    subCommand = subCommand.Parent;
                }
            });
        }
コード例 #4
0
        public virtual void Apply(ConventionContext context)
        {
            var modelAccessor = context.ModelAccessor;

            if (context.ModelType == null || modelAccessor == null)
            {
                return;
            }

            var attributes = context.ModelType.GetTypeInfo().GetCustomAttributes <SubcommandAttribute>();

            foreach (var attribute in attributes)
            {
                var contextArgs = new object[] { context, attribute };
                foreach (var type in attribute.Types)
                {
                    AssertSubcommandIsNotCycled(type, context.Application);

                    var impl = s_addSubcommandMethod.MakeGenericMethod(type);
                    try
                    {
                        impl.Invoke(this, contextArgs);
                    }
                    catch (TargetInvocationException ex)
                    {
                        // unwrap
                        throw ex.InnerException ?? ex;
                    }
                }
            }
        }
コード例 #5
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            var props = ReflectionHelper.GetProperties(context.ModelType);

            foreach (var prop in props)
            {
                var attr = prop.GetCustomAttribute <OptionAttribute>();
                if (attr == null)
                {
                    continue;
                }

                EnsureDoesNotHaveHelpOptionAttribute(prop);
                EnsureDoesNotHaveVersionOptionAttribute(prop);
                EnsureDoesNotHaveArgumentAttribute(prop);

                var option = attr.Configure(context.Application, prop);
                AddOption(context, option, prop);
            }
        }
コード例 #6
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            var subcommands = context.ModelType.GetTypeInfo().GetCustomAttributes <SubcommandAttribute>();

            if (subcommands == null)
            {
                return;
            }

            foreach (var subcommand in subcommands)
            {
                var impl = s_addSubcommandMethod.MakeGenericMethod(subcommand.CommandType);
                try
                {
                    impl.Invoke(this, new object[] { context, subcommand });
                }
                catch (TargetInvocationException ex)
                {
                    // unwrap
                    throw ex.InnerException ?? ex;
                }
            }
        }
コード例 #7
0
        public virtual void Apply(ConventionContext context)
        {
            var modelAccessor = context.ModelAccessor;

            if (context.ModelType == null || modelAccessor == null)
            {
                return;
            }

            var parentProp = context.ModelType.GetTypeInfo().GetProperty("Parent", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            if (parentProp == null)
            {
                return;
            }

            var setter = ReflectionHelper.GetPropertySetter(parentProp);

            context.Application.OnParsingComplete(r =>
            {
                CommandLineApplication?subcommand = r.SelectedCommand;
                while (subcommand != null)
                {
                    if (ReferenceEquals(context.Application, subcommand))
                    {
                        if (subcommand.Parent is IModelAccessor parentAccessor)
                        {
                            setter(modelAccessor.GetModel(), parentAccessor.GetModel());
                        }
                        return;
                    }
                    subcommand = subcommand.Parent;
                }
            });
        }
コード例 #8
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            var modelAccessor = context.ModelAccessor;

            if (context.ModelType == null || modelAccessor == null)
            {
                return;
            }

            var prop = context.ModelType.GetProperty("RemainingArguments", PropertyBindingFlags);

            prop ??= context.ModelType.GetProperty("RemainingArgs", PropertyBindingFlags);
            if (prop == null)
            {
                return;
            }

            var setter = ReflectionHelper.GetPropertySetter(prop);

            if (prop.PropertyType == typeof(string[]))
            {
                context.Application.OnParsingComplete(r =>
                                                      setter(modelAccessor.GetModel(), r.SelectedCommand.RemainingArguments.ToArray()));
                return;
            }

            if (!typeof(IReadOnlyList <string>).IsAssignableFrom(prop.PropertyType))
            {
                throw new InvalidOperationException(Strings.RemainingArgsPropsIsUnassignable(context.ModelType));
            }

            context.Application.OnParsingComplete(r =>
                                                  setter(modelAccessor.GetModel(), r.SelectedCommand.RemainingArguments));
        }
コード例 #9
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            context.Application.OnExecute(async() => await this.OnExecute(context));
        }
コード例 #10
0
        private void AddSubcommandImpl <TSubCommand>(ConventionContext context, SubcommandAttribute subcommand)
            where TSubCommand : class, new()
        {
            if (context.Application.Commands.Any(c => c.Name.Equals(subcommand.Name, StringComparison.OrdinalIgnoreCase)))
            {
                throw new InvalidOperationException(Strings.DuplicateSubcommandName(subcommand.Name));
            }

            context.Application.Command <TSubCommand>(subcommand.Name, subcommand.Configure);
        }
コード例 #11
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            var versionOptionFromMember = context.ModelType.GetTypeInfo().GetCustomAttribute <VersionOptionFromMemberAttribute>();

            versionOptionFromMember?.Configure(context.Application, context.ModelType, context.ModelAccessor.GetModel);
        }
コード例 #12
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            var attribute = context.ModelType.GetTypeInfo().GetCustomAttribute <CommandAttribute>();

            attribute?.Configure(context.Application);
        }
コード例 #13
0
        public virtual void Apply(ConventionContext context)
        {
            var modelAccessor = context.ModelAccessor;

            if (context.ModelType == null || modelAccessor == null)
            {
                return;
            }

            var versionOptionAttrOnType = context.ModelType.GetTypeInfo().GetCustomAttribute <VersionOptionAttribute>();

            versionOptionAttrOnType?.Configure(context.Application);

            var props = ReflectionHelper.GetProperties(context.ModelType);

            VersionOptionAttribute?versionOptionAttr = null;
            PropertyInfo?          property          = null;

            foreach (var prop in props)
            {
                var attr = prop.GetCustomAttribute <VersionOptionAttribute>();
                if (attr == null)
                {
                    continue;
                }

                if (versionOptionAttr != null)
                {
                    throw new InvalidOperationException(Strings.MultipleVersionOptionPropertiesFound);
                }

                if (versionOptionAttrOnType != null)
                {
                    throw new InvalidOperationException(Strings.VersionOptionOnTypeAndProperty);
                }

                versionOptionAttr = attr;
                property          = prop;

                EnsureDoesNotHaveOptionAttribute(prop);
                EnsureDoesNotHaveHelpOptionAttribute(prop);
                EnsureDoesNotHaveArgumentAttribute(prop);
            }

            if (versionOptionAttr == null || property == null)
            {
                return;
            }

            var option = versionOptionAttr.Configure(context.Application);

            AddOption(context, option, property);
        }
コード例 #14
0
        private void ApplyImpl <TModel>(ConventionContext context)
            where TModel : class
        {
            var constructors = typeof(TModel).GetConstructors(BindingFlags.Public | BindingFlags.Instance);

            var factory = FindMatchedConstructor <TModel>(constructors, context.Application,
                                                          constructors.Length == 1);

            if (factory != null)
            {
                ((CommandLineApplication <TModel>)context.Application).ModelFactory = factory;
            }
        }
コード例 #15
0
        private async Task <int> OnExecute(ConventionContext context)
        {
            const BindingFlags binding = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;

            var        typeInfo = context.ModelType.GetTypeInfo();
            MethodInfo?method;
            MethodInfo?asyncMethod;

            try
            {
                method      = typeInfo.GetMethod("OnExecute", binding);
                asyncMethod = typeInfo.GetMethod("OnExecuteAsync", binding);
            }
            catch (AmbiguousMatchException ex)
            {
                throw new InvalidOperationException(Strings.AmbiguousOnExecuteMethod, ex);
            }

            if (method != null && asyncMethod != null)
            {
                throw new InvalidOperationException(Strings.AmbiguousOnExecuteMethod);
            }

            method ??= asyncMethod;

            if (method == null)
            {
                throw new InvalidOperationException(Strings.NoOnExecuteMethodFound);
            }

            var arguments     = ReflectionHelper.BindParameters(method, context.Application);
            var modelAccessor = context.ModelAccessor;

            if (modelAccessor == null)
            {
                throw new InvalidOperationException(Strings.ConventionRequiresModel);
            }
            var model = modelAccessor.GetModel();

            if (method.ReturnType == typeof(Task) || method.ReturnType == typeof(Task <int>))
            {
                return(await InvokeAsync(method, model, arguments));
            }
            else if (method.ReturnType == typeof(void) || method.ReturnType == typeof(int))
            {
                return(Invoke(method, model, arguments));
            }

            throw new InvalidOperationException(Strings.InvalidOnExecuteReturnType(method.Name));
        }
コード例 #16
0
        /// <inheritdoc />
        public void Apply(ConventionContext context)
        {
            if (context.Application.OptionHelp != null)
            {
                return;
            }

            if (context.ModelType != null)
            {
                var typeInfo = context.ModelType.GetTypeInfo();
                if (typeInfo.GetCustomAttribute <SuppressDefaultHelpOptionAttribute>() != null ||
                    typeInfo.Assembly.GetCustomAttribute <SuppressDefaultHelpOptionAttribute>() != null)
                {
                    return;
                }
            }

            var help = new CommandOption(_template, CommandOptionType.NoValue)
            {
                Description = Strings.DefaultHelpOptionDescription,

                // the convention will run on each subcommand automatically.
                // it is better to run the command on each to check for overlap
                // or already set options to avoid conflict
                Inherited = false,
            };

            foreach (var opt in context.Application.GetOptions())
            {
                if (string.Equals(help.LongName, opt.LongName))
                {
                    help.LongName = null;
                }
                if (string.Equals(help.ShortName, opt.ShortName))
                {
                    help.ShortName = null;
                }

                if (string.Equals(help.SymbolName, opt.SymbolName))
                {
                    help.SymbolName = null;
                }
            }

            if (help.LongName != null || help.ShortName != null || help.SymbolName != null)
            {
                context.Application.OptionHelp = help;
                context.Application.Options.Add(help);
            }
        }
コード例 #17
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (_additionalServices != null)
            {
                context.Application.AdditionalServices = _additionalServices;
            }

            if (context.ModelType == null)
            {
                return;
            }

            s_applyMethod.MakeGenericMethod(context.ModelType).Invoke(this, new object[] { context });
        }
コード例 #18
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            var props = ReflectionHelper.GetProperties(context.ModelType);

            if (props == null)
            {
                return;
            }

            var argOrder     = new SortedList <int, CommandArgument>();
            var argPropOrder = new Dictionary <int, PropertyInfo>();

            foreach (var prop in props)
            {
                var argumentAttr = prop.GetCustomAttribute <ArgumentAttribute>();
                if (argumentAttr == null)
                {
                    continue;
                }

                if (prop.GetCustomAttributes().OfType <OptionAttributeBase>().Any())
                {
                    throw new InvalidOperationException(
                              Strings.BothOptionAndArgumentAttributesCannotBeSpecified(prop));
                }

                AddArgument(prop, argumentAttr, context, argOrder, argPropOrder);
            }

            foreach (var arg in argOrder)
            {
                if (context.Application.Arguments.Count > 0)
                {
                    var lastArg = context.Application.Arguments[context.Application.Arguments.Count - 1];
                    if (lastArg.MultipleValues)
                    {
                        throw new InvalidOperationException(
                                  Strings.OnlyLastArgumentCanAllowMultipleValues(lastArg.Name));
                    }
                }

                context.Application.Arguments.Add(arg.Value);
            }
        }
コード例 #19
0
        /// <inheritdoc />
        public void Apply(ConventionContext context)
        {
            if (!string.IsNullOrEmpty(context.Application.Name))
            {
                return;
            }

            if (context.ModelType == null)
            {
                return;
            }

            var commandName = GetCommandName(context.ModelType.Name);

            if (!string.IsNullOrEmpty(commandName))
            {
                context.Application.Name = commandName;
            }
        }
コード例 #20
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            var attribute = context.ModelType.GetTypeInfo().GetCustomAttribute <CommandAttribute>();

            attribute?.Configure(context.Application);

            foreach (var subcommand in context.Application.Commands)
            {
                if (subcommand is IModelAccessor subcommandAccessor)
                {
                    Apply(new ConventionContext(subcommand, subcommandAccessor.GetModelType()));
                }
            }
        }
コード例 #21
0
        /// <inheritdoc />
        public virtual void Apply(ConventionContext context)
        {
            if (context.Application.Name != null)
            {
                return;
            }

            var assembly = Assembly.GetEntryAssembly();

            if (assembly == null && context.ModelType != null)
            {
                assembly = context.ModelType.GetTypeInfo().Assembly;
            }

            if (assembly != null)
            {
                context.Application.Name = assembly.GetName().Name;
            }
        }
コード例 #22
0
        /// <inheritdoc />
        public void Apply(ConventionContext context)
        {
            if (context.ModelType == null)
            {
                return;
            }

            foreach (var attr in context.ModelType.GetTypeInfo().GetCustomAttributes().OfType <IConvention>())
            {
                attr.Apply(context);
            }

            var members = ReflectionHelper.GetMembers(context.ModelType);

            foreach (var member in members)
            {
                foreach (var attr in member.GetCustomAttributes().OfType <IMemberConvention>())
                {
                    attr.Apply(context, member);
                }
            }
        }
コード例 #23
0
        private void ApplyImpl <TModel>(ConventionContext context)
            where TModel : class
        {
            var constructors = typeof(TModel)
                               .GetTypeInfo()
                               .GetConstructors(BindingFlags.Public | BindingFlags.Instance);

            if (constructors.Length == 0)
            {
                throw new InvalidOperationException("Could not find any public constructors on " + typeof(TModel).FullName);
            }

            // find the constructor with the most parameters first
            foreach (var ctorCandidate in constructors.OrderByDescending(c => c.GetParameters().Count()))
            {
                var parameters = ctorCandidate.GetParameters().ToArray();
                var args       = new object[parameters.Length];
                var matched    = false;
                for (var i = 0; i < parameters.Length; i++)
                {
                    var paramType = parameters[i].ParameterType;
                    var service   = ((IServiceProvider)context.Application).GetService(paramType);
                    if (service == null)
                    {
                        break;
                    }
                    args[i] = service;
                    matched = i == parameters.Length - 1;
                }

                if (matched)
                {
                    (context.Application as CommandLineApplication <TModel>).ModelFactory =
                        () => (TModel)ctorCandidate.Invoke(args);
                    return;
                }
            }
        }
コード例 #24
0
 private void AddSubcommandImpl <TSubCommand>(ConventionContext context)
     where TSubCommand : class
 {
     context.Application.Command <TSubCommand>(null !, null !); // Hmm, should probably rethink this...
 }
コード例 #25
0
        private void AddArgument(PropertyInfo prop,
                                 ArgumentAttribute argumentAttr,
                                 ConventionContext convention,
                                 SortedList <int, CommandArgument> argOrder,
                                 Dictionary <int, PropertyInfo> argPropOrder)
        {
            var argument = argumentAttr.Configure(prop);

            foreach (var attr in prop.GetCustomAttributes().OfType <ValidationAttribute>())
            {
                argument.Validators.Add(new AttributeValidator(attr));
            }

            argument.MultipleValues =
                prop.PropertyType.IsArray ||
                (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType) &&
                 prop.PropertyType != typeof(string));

            if (argPropOrder.TryGetValue(argumentAttr.Order, out var otherProp))
            {
                throw new InvalidOperationException(
                          Strings.DuplicateArgumentPosition(argumentAttr.Order, prop, otherProp));
            }

            argPropOrder.Add(argumentAttr.Order, prop);
            argOrder.Add(argumentAttr.Order, argument);

            var setter = ReflectionHelper.GetPropertySetter(prop);

            if (argument.MultipleValues)
            {
                convention.Application.OnParsingComplete(r =>
                {
                    var collectionParser = CollectionParserProvider.Default.GetParser(
                        prop.PropertyType,
                        convention.Application.ValueParsers);
                    if (collectionParser == null)
                    {
                        throw new InvalidOperationException(Strings.CannotDetermineParserType(prop));
                    }

                    if (argument.Values.Count == 0)
                    {
                        return;
                    }

                    if (r.SelectedCommand is IModelAccessor cmd)
                    {
                        setter.Invoke(cmd.GetModel(), collectionParser.Parse(argument.Name, argument.Values));
                    }
                });
            }
            else
            {
                convention.Application.OnParsingComplete(r =>
                {
                    var parser = convention.Application.ValueParsers.GetParser(prop.PropertyType);
                    if (parser == null)
                    {
                        throw new InvalidOperationException(Strings.CannotDetermineParserType(prop));
                    }

                    if (argument.Values.Count == 0)
                    {
                        return;
                    }

                    if (r.SelectedCommand is IModelAccessor cmd)
                    {
                        setter.Invoke(
                            cmd.GetModel(),
                            parser.Parse(
                                argument.Name,
                                argument.Value,
                                convention.Application.ValueParsers.ParseCulture));
                    }
                });
            }
        }
コード例 #26
0
        private protected void AddOption(ConventionContext context, CommandOption option, PropertyInfo prop)
        {
            foreach (var attr in prop.GetCustomAttributes().OfType <ValidationAttribute>())
            {
                option.Validators.Add(new AttributeValidator(attr));
            }

            if (option.OptionType == CommandOptionType.NoValue && prop.PropertyType != typeof(bool))
            {
                throw new InvalidOperationException(Strings.NoValueTypesMustBeBoolean);
            }

            if (!string.IsNullOrEmpty(option.ShortName))
            {
                if (context.Application._shortOptions.TryGetValue(option.ShortName, out var otherProp))
                {
                    throw new InvalidOperationException(
                              Strings.OptionNameIsAmbiguous(option.ShortName, prop, otherProp));
                }
                context.Application._shortOptions.Add(option.ShortName, prop);
            }

            if (!string.IsNullOrEmpty(option.LongName))
            {
                if (context.Application._longOptions.TryGetValue(option.LongName, out var otherProp))
                {
                    throw new InvalidOperationException(
                              Strings.OptionNameIsAmbiguous(option.LongName, prop, otherProp));
                }
                context.Application._longOptions.Add(option.LongName, prop);
            }

            var setter = ReflectionHelper.GetPropertySetter(prop);

            switch (option.OptionType)
            {
            case CommandOptionType.MultipleValue:
                var collectionParser = CollectionParserProvider.Default.GetParser(prop.PropertyType, context.Application.ValueParsers);
                if (collectionParser == null)
                {
                    throw new InvalidOperationException(Strings.CannotDetermineParserType(prop));
                }
                context.Application.OnParsingComplete(_ =>
                                                      setter.Invoke(context.ModelAccessor.GetModel(), collectionParser.Parse(option.LongName, option.Values)));
                break;

            case CommandOptionType.SingleOrNoValue:
            case CommandOptionType.SingleValue:
                var parser = context.Application.ValueParsers.GetParser(prop.PropertyType);
                if (parser == null)
                {
                    throw new InvalidOperationException(Strings.CannotDetermineParserType(prop));
                }
                context.Application.OnParsingComplete(_ =>
                {
                    if (!option.HasValue())
                    {
                        return;
                    }
                    setter.Invoke(context.ModelAccessor.GetModel(), parser.Parse(option.LongName, option.Value(), context.Application.ValueParsers.ParseCulture));
                });
                break;

            case CommandOptionType.NoValue:
                context.Application.OnParsingComplete(_ => setter.Invoke(context.ModelAccessor.GetModel(), option.HasValue()));
                break;

            default:
                throw new NotImplementedException();
            }
        }
コード例 #27
0
 private void AddSubcommandImpl <TSubCommand>(ConventionContext context)
     where TSubCommand : class
 {
     context.Application.Command <TSubCommand>(null, null);
 }
コード例 #28
0
        private protected void AddOption(ConventionContext context, CommandOption option, PropertyInfo prop)
        {
            var modelAccessor = context.ModelAccessor;

            if (modelAccessor == null)
            {
                throw new InvalidOperationException(Strings.ConventionRequiresModel);
            }

            foreach (var attr in prop.GetCustomAttributes().OfType <ValidationAttribute>())
            {
                option.Validators.Add(new AttributeValidator(attr));
            }

            if (option.OptionType == CommandOptionType.NoValue &&
                prop.PropertyType != typeof(bool) &&
                prop.PropertyType != typeof(bool?) &&
                prop.PropertyType != typeof(bool[]))
            {
                throw new InvalidOperationException(Strings.NoValueTypesMustBeBoolean);
            }

            if (!string.IsNullOrEmpty(option.ShortName))
            {
                if (context.Application._shortOptions.TryGetValue(option.ShortName, out var otherProp))
                {
                    throw new InvalidOperationException(
                              Strings.OptionNameIsAmbiguous(option.ShortName, prop, otherProp));
                }
                context.Application._shortOptions.Add(option.ShortName, prop);
            }

            if (!string.IsNullOrEmpty(option.LongName))
            {
                if (context.Application._longOptions.TryGetValue(option.LongName, out var otherProp))
                {
                    throw new InvalidOperationException(
                              Strings.OptionNameIsAmbiguous(option.LongName, prop, otherProp));
                }
                context.Application._longOptions.Add(option.LongName, prop);
            }

            var getter = ReflectionHelper.GetPropertyGetter(prop);
            var setter = ReflectionHelper.GetPropertySetter(prop);

            switch (option.OptionType)
            {
            case CommandOptionType.MultipleValue:
                context.Application.OnParsingComplete(_ =>
                {
                    var collectionParser =
                        CollectionParserProvider.Default.GetParser(prop.PropertyType,
                                                                   context.Application.ValueParsers);

                    if (collectionParser == null)
                    {
                        throw new InvalidOperationException(Strings.CannotDetermineParserType(prop));
                    }

                    if (!option.HasValue())
                    {
                        if (!ReflectionHelper.IsSpecialValueTupleType(prop.PropertyType, out var type))
                        {
                            if (getter.Invoke(modelAccessor.GetModel()) is IEnumerable <object> values)
                            {
                                foreach (var value in values)
                                {
                                    option.TryParse(value?.ToString());
                                }
                                option.DefaultValue = string.Join(", ", values.Select(x => x?.ToString()));
                            }
                        }
                    }
                    else
                    {
                        setter.Invoke(modelAccessor.GetModel(), collectionParser.Parse(option.LongName, option.Values));
                    }
                });
                break;

            case CommandOptionType.SingleOrNoValue:
            case CommandOptionType.SingleValue:
                context.Application.OnParsingComplete(_ =>
                {
                    var parser = context.Application.ValueParsers.GetParser(prop.PropertyType);
                    if (parser == null)
                    {
                        throw new InvalidOperationException(Strings.CannotDetermineParserType(prop));
                    }

                    if (!option.HasValue())
                    {
                        if (!ReflectionHelper.IsSpecialValueTupleType(prop.PropertyType, out var type))
                        {
                            var value = getter.Invoke(modelAccessor.GetModel());

                            if (value != null)
                            {
                                option.TryParse(value.ToString());
                                option.DefaultValue = value.ToString();
                            }
                        }
                    }
                    else
                    {
                        setter.Invoke(modelAccessor.GetModel(), parser.Parse(option.LongName, option.Value(), context.Application.ValueParsers.ParseCulture));
                    }
                });
                break;

            case CommandOptionType.NoValue:
                context.Application.OnParsingComplete(_ =>
                {
                    if (prop.PropertyType == typeof(bool[]))
                    {
                        if (!option.HasValue())
                        {
                            setter.Invoke(modelAccessor.GetModel(), Util.EmptyArray <bool>());
                        }

                        var count = new bool[option.Values.Count];
                        for (var i = 0; i < count.Length; i++)
                        {
                            count[i] = true;
                        }

                        setter.Invoke(modelAccessor.GetModel(), count);
                    }
                    else
                    {
                        if (!option.HasValue())
                        {
                            return;
                        }

                        setter.Invoke(modelAccessor.GetModel(), option.HasValue());
                    }
                });
                break;

            default:
                throw new NotImplementedException();
            }
        }