private void BuildParameters(CommandAttribute attribute, ParameterInfo[] parameterInfo) { if (parameterInfo.Length == 0) { throw new CommandException($"No parameters for CommandHandler {string.Join(',', attribute.Commands)}, ICommandContext must at least be supplied!"); } // first parameter must be the context if (!typeof(ICommandContext).IsAssignableFrom(parameterInfo[0].ParameterType)) { throw new CommandException($"First parameter for CommandHandler {string.Join(',', attribute.Commands)} must be ICommandContext!"); } var builder = ImmutableList.CreateBuilder <CommandParameter>(); foreach (ParameterInfo parameter in parameterInfo.Skip(1)) { Type underlyingType = Nullable.GetUnderlyingType(parameter.ParameterType); // if parameter has the ParameterAttribute attribute the converter overload will be used from here // otherwise it will come from the default for the parameter type ParameterAttribute parameterAttribute = parameter.GetCustomAttribute <ParameterAttribute>(); IParameterConvert converter = parameterAttribute?.Converter != null ? CommandManager.Instance.GetParameterConverter(parameterAttribute.Converter) : CommandManager.Instance.GetParameterConverterDefault(underlyingType ?? parameter.ParameterType); if (converter == null) { throw new ArgumentException($"No parameter converter found for parameter {parameter.Name} in CommandHandler {string.Join(',', attribute.Commands)}!"); } // parameter is considered optional if specified explicitly or if is a nullable type builder.Add(new CommandParameter(parameter.ParameterType, converter, underlyingType != null || (parameterAttribute?.IsOptional ?? false))); } parameters = builder.ToImmutable(); // check that optional parameters are last int index = parameters.FindIndex(p => p.IsOptional); if (index == -1) { return; } for (int i = index; i < parameters.Count; i++) { if (!parameters[i].IsOptional) { throw new CommandException($"Optional parameters must come after mandatory parameters in CommandHandler {string.Join(',', attribute.Commands)}!"); } } }
/// <summary> /// Create a new <see cref="CommandParameter"/> of the supplied <see cref="System.Type"/> with optional <see cref="IParameterConvert"/> overload and optional flag. /// </summary> public CommandParameter(Type type, IParameterConvert converter, bool isOptional) { Type = type; Converter = converter; IsOptional = isOptional; }