public T Map <T>(T command, ICommandLine commandLine) where T : IConsoleCommand { if (command == null) { throw new ArgumentNullException(nameof(command)); } if (commandLine == null) { throw new ArgumentNullException(nameof(commandLine)); } // "Single" is fine because it's not possible to misconfigure the factory if commander-module is used so there is always a matching registration. var registration = _registrations.Single(r => r.CommandType == command.GetType()); IEnumerable <string> GetValues(CommandParameter parameter) { if (parameter.Metadata.Position > CommandLine.CommandIndex) { return(commandLine.Anonymous().Skip(parameter.Metadata.Position).Take(1)); } if (commandLine.Contains(parameter.Name)) { return(commandLine[parameter.Name]); } return(null); } foreach (var parameter in registration) { _logger.Trace($"Mapping parameter {parameter.Name}."); var values = GetValues(parameter)?.ToList(); // If parameter does not exist at all... if (values is null) { // ...check if it should exist. if (parameter.IsRequired) { throw ($"ArgumentNotFound{nameof(Exception)}", $"The required argument {parameter.Name} was not found.").ToDynamicException(); } if (parameter.DefaultValue.IsNotNull()) { parameter.SetValue(command, _converter.Convert(parameter.DefaultValue, parameter.Type)); } } else { if (parameter.Type == typeof(bool)) { var flag = values.SingleOrDefault(); // User did not specify any value but a flag alone. if (flag is null) { if (parameter.DefaultValue is bool defaultValue) { parameter.SetValue(command, !defaultValue); } else { // If DefaultValue is not set then the default is false. This negates it. parameter.SetValue(command, true); } } else { var value = _converter.Convert(flag, typeof(bool)); parameter.SetValue(command, value); } } else { // Parameter is required but not values are specified. This is an error. if (parameter.IsRequired && values.Empty()) { throw ($"ArgumentNotFound{nameof(Exception)}", $"The required argument {parameter.Name} was not found.").ToDynamicException(); } var convertible = parameter.Type.IsEnumerable(ignore: typeof(string)) ? (object)values : values.SingleOrDefault(); var value = _converter.Convert(convertible, parameter.Type); parameter.SetValue(command, value); } } } return(command); }