/// <summary>
        /// Loads all methods tagged with <see cref="CommandAttribute"/> from a given type, be they
        /// public or private.
        /// </summary>
        /// <param name="type">Type where to load commands from</param>
        /// <param name="instance">Instance to use when invoking the methods (null for static classes)</param>
        public void LoadCommands(Type type, object instance)
        {
            if (type is null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            // Find static/non-static methods (choose between static and instance by the presence of
            // a non-null instance)
            foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
                     .OrderBy(method => method.Name))
            {
                if (method.IsDefined(typeof(CommandAttribute)))
                {
                    // Create a single instance of the command (will validate and compile in the constructor)
                    var command = new CompiledCommand(method, instance);
                    CommandList.Add(command);

                    // Get all command attributes and then register all of them with the same command
                    foreach (var attr in method.GetCustomAttributes <CommandAttribute>())
                    {
                        if (CommandLookupTable.ContainsKey(attr.Name) && !attr.Overwrite)
                        {
                            var existingCommand = (CompiledCommand)CommandLookupTable[attr.Name];
                            throw new CommandDefinitionException(method, $"Command name {attr.Name} is already defined in: {GetFullName(existingCommand.Method, existingCommand.Instance)}");
                        }
                        CommandLookupTable[attr.Name] = command;
                    }
                }
            }
        }
        /// <summary>
        /// Registers a command to end the command loop with the provided names
        /// </summary>
        /// <param name="names">All possible names for the exit command</param>
        public void AddStopCommand(params string[] names)
        {
            if (names == null)
            {
                throw new ArgumentNullException(nameof(names));
            }
            if (names.Length < 1)
            {
                throw new ArgumentException("No names provided.", nameof(names));
            }

            var exitCommand = new CompiledCommand(
                typeof(ConsoleCommandManager).GetMethod(nameof(Stop)),
                this,
                names,
                "Exits this command loop.");

            CommandList.Add(exitCommand);
            foreach (var name in names)
            {
                CommandLookupTable[name] = exitCommand;
            }
            HasExitCommand = true;
        }