private static IEnumerable <CommandParameter> GetParameters(CommandInfo command) { var result = new List <CommandParameter>(); var argumentPosition = 0; // We need to get parameters in order of the class where they were defined. // We assign each inheritance level a value that is used to properly sort the // arguments when iterating over them. IEnumerable <OrderedProperties> GetPropertiesInOrder() { var current = command.SettingsType; var level = 0; var sortOrder = 0; while (current.BaseType != null) { yield return(new OrderedProperties(level, sortOrder, current.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))); current = current.BaseType; // Things get a little bit complicated now. // Only consider a setting's base type part of the // setting, if there isn't a parent command that implements // the setting's base type. This might come back to bite us :) var currentCommand = command.Parent; while (currentCommand != null) { if (currentCommand.SettingsType == current) { level--; break; } currentCommand = currentCommand.Parent; } sortOrder--; } } var groups = GetPropertiesInOrder(); foreach (var group in groups.OrderBy(x => x.Level).ThenBy(x => x.SortOrder)) { var parameters = new List <CommandParameter>(); foreach (var property in group.Properties) { if (property.IsDefined(typeof(CommandOptionAttribute))) { var attribute = property.GetCustomAttribute <CommandOptionAttribute>(); if (attribute != null) { var option = BuildOptionParameter(property, attribute); // Any previous command has this option defined? if (command.HaveParentWithOption(option)) { // Do we allow it to exist on this command as well? if (command.AllowParentOption(option)) { option.IsShadowed = true; parameters.Add(option); } } else { // No parent have this option. parameters.Add(option); } } } else if (property.IsDefined(typeof(CommandArgumentAttribute))) { var attribute = property.GetCustomAttribute <CommandArgumentAttribute>(); if (attribute != null) { var argument = BuildArgumentParameter(property, attribute); // Any previous command has this argument defined? // In that case, we should not assign the parameter to this command. if (!command.HaveParentWithArgument(argument)) { parameters.Add(argument); } } } } // Update the position for the parameters. foreach (var argument in parameters.OfType <CommandArgument>().OrderBy(x => x.Position)) { argument.Position = argumentPosition++; } // Add all parameters to the result. foreach (var groupResult in parameters) { result.Add(groupResult); } } return(result); }