private static bool ValidateCommand(ConsoleCommand command, CommandList commands, out ConsoleExecutingAssembly instance, out Dictionary<string, ConsoleExecutingMethod> methodDictionary) { instance = null; methodDictionary = null; // Validate the command name: var found = false; foreach (var key in commands.Keys.Where(key => key.Namespace == command.LibraryClassName)) { found = true; instance = key; methodDictionary = commands[key]; break; } if (!found) { return false; } if (!methodDictionary.ContainsKey(command.Name)) { var newCommand = char.ToUpperInvariant(command.Name[0]) + command.Name.Substring(1); if (!methodDictionary.ContainsKey(newCommand)) { return false; } command.Name = char.ToUpperInvariant(command.Name[0]) + command.Name.Substring(1); } return true; }
private static bool BuildCommand(ConsoleCommand command, ConsoleExecutingAssembly instance, IReadOnlyDictionary<string, ConsoleExecutingMethod> methodDictionary, out object[] inputArgs, out Type typeInfo, out string errorMessage) { inputArgs = null; typeInfo = null; errorMessage = null; // Make sure the correct number of required arguments are provided: // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ var methodParameterValueList = new List<object>(); IEnumerable<ParameterInfo> paramInfoList = methodDictionary[command.Name].Parameters.ToList(); // Validate proper # of required arguments provided. Some may be optional: var requiredParams = paramInfoList.Where(p => !p.IsOptional).ToList(); var optionalParams = paramInfoList.Where(p => p.IsOptional).ToList(); var requiredCount = requiredParams.Count; var optionalCount = optionalParams.Count; var providedCount = command.Arguments.Count(); if (requiredCount > providedCount) { var message = new StringBuilder(); message.AppendLine( $"Missing required argument. {requiredCount} required, {optionalCount} optional, {providedCount} provided"); if (requiredCount > 0) { message.AppendLine(""); message.AppendLine("Required"); foreach (var required in requiredParams) { message.Append(required.Name); message.Append(":"); message.AppendLine(required.ParameterType.ToString()); } } if (optionalParams.Count > 0) { message.AppendLine(""); message.AppendLine("Optional"); foreach (var required in optionalParams) { message.Append(required.Name); message.Append(":"); message.Append(required.ParameterType); message.Append(":"); message.AppendLine(required.RawDefaultValue?.ToString() ?? "null"); } } errorMessage = message.ToString(); return false; } // Make sure all arguments are coerced to the proper type, and that there is a // value for every method parameter. The InvokeMember method fails if the number // of arguments provided does not match the number of parameters in the // method signature, even if some are optional: // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (paramInfoList.Any()) { // Populate the list with default values: methodParameterValueList.AddRange(paramInfoList.Select(param => param.DefaultValue)); // Now walk through all the arguments passed from the console and assign // accordingly. Any optional arguments not provided have already been set to // the default specified by the method signature: for (var i = 0; i < command.Arguments.Count(); i++) { var methodParam = paramInfoList.ElementAt(i); var typeRequired = methodParam.ParameterType; try { // Coming from the Console, all of our arguments are passed in as // strings. Coerce to the type to match the method parameter: var value = ConsoleParseArgument.CoerceArgument(typeRequired, command.Arguments.ElementAt(i)); methodParameterValueList.RemoveAt(i); methodParameterValueList.Insert(i, value); } // ReSharper disable once UncatchableException catch (ArgumentException ex) { var argumentName = methodParam.Name; var argumentTypeName = typeRequired.Name; var message = $"The value passed for argument '{argumentName}' cannot be parsed to type '{argumentTypeName}'"; throw new ArgumentException(message, ex); } } } // Set up to invoke the method using reflection: // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Need the full Namespace for this: var commandLibraryClass = instance.Instance.GetType(); if (methodParameterValueList.Count > 0) { inputArgs = methodParameterValueList.ToArray(); } typeInfo = commandLibraryClass; return true; }