/// <summary> /// Recursively builds the syntax for the command. /// </summary> /// <param name="commandType">The current type of command.</param> /// <param name="command">The command being built.</param> /// <remarks> /// This method recursively works its way up a <see cref="Command"/> object's inheritance hierarchy. It stops /// when the next base class is not a subclass of <see cref="Command"/>. This allows for nested commands to be /// built. /// </remarks> private void BuildCommandFromType(Type commandType, Command command) { var syntaxAttribute = this.GetSyntaxAttribute(commandType); if (syntaxAttribute == null) { return; } var commandSyntaxAttribute = syntaxAttribute as CommandSyntaxAttribute; if (commandSyntaxAttribute == null) { return; } var baseType = commandType.BaseType; if (baseType != null && baseType.IsSubclassOf(typeof(Command))) { this.BuildCommandFromType(baseType, command); } var fileName = commandSyntaxAttribute.GetFullPath(); if (fileName.Contains(" ")) { fileName = string.Format("\"{0}\"", fileName); } if (commandType.BaseType == typeof(Command)) { this.FileName = fileName; } else { this.arguments.AppendFormat(fileName + ' '); } var properties = commandType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); var parameters = new List<Parameter>(); foreach (var property in properties) { var parameterSyntaxAttribute = (ParameterSyntaxAttribute)this.GetSyntaxAttribute(property); if (parameterSyntaxAttribute == null) { continue; } var returnType = property.GetGetMethod().ReturnType; if (returnType.IsSubclassOf(typeof(ValueType)) && Nullable.GetUnderlyingType(returnType) == null) { const string MESSAGE = "The return type for a parameter isn't nullable. All properties adorned " + "with a ParameterSyntaxAttribute must be nullable. For primitives, consider suffixing the " + "type declaration with a question mark (?)."; throw new SyntaxException(MESSAGE, null, parameterSyntaxAttribute); } var argument = property.GetValue(command, null); if (argument == null && parameterSyntaxAttribute.Required) { const string MESSAGE = "A parameter was marked as required but an argument was never given."; throw new SyntaxException(MESSAGE, null, parameterSyntaxAttribute); } var parameterType = parameterSyntaxAttribute.ParameterType; try { var parameterInstance = (Parameter)Activator.CreateInstance( parameterType, parameterSyntaxAttribute, argument); parameters.Add(parameterInstance); } catch (Exception e) { const string MESSAGE = "Could not create an instance of the parameter type. If you're using a " + "custom parameter type, make sure it doesn't implement any new constructors."; throw new SyntaxException(MESSAGE, e, parameterSyntaxAttribute); } } parameters.Sort(); foreach (var parameter in parameters) { var parameterString = parameter.ToString(); if (string.IsNullOrEmpty(parameterString)) { continue; } this.arguments.Append(parameterString + ' '); } }
/// <summary> /// Initializes a new instance of the CommandException class. /// </summary> /// <para>Takes in an error message, an inner exception, and a <see cref="Command"/> object.</para> /// <param name="message">The error message associated with the exception.</param> /// <param name="inner">The inner exception.</param> /// <param name="command">The <see cref="Command"/> object associated with the exception.</param> public CommandException(string message, Exception inner, Command command) : base(message, inner) { this.command = command; }
/// <summary> /// Initializes a new instance of the SyntaxBuilder class. /// </summary> /// <param name="command">Command from which to build the syntax.</param> public SyntaxBuilder(Command command) { this.command = command; this.BuildSyntax(); }