/// <summary>Invokes a command on an object by matching the command to a method using reflection.</summary>
        /// <typeparam name="TObject">The object type on which to search the method. This can be used to pass an interface or a base type.</typeparam>
        /// <param name="executor">The object on which to invoke the method.</param>
        /// <param name="argumentCollection">The command argument list.</param>
        /// <returns>The value returned by the invoked method.</returns>
        /// <exception cref="OvermindException">Thrown if the command could not be matched to an executor method.</exception>
        public object Invoke <TObject>(TObject executor, IList <string> argumentCollection)
        {
            const int argumentOffset = 2;             // To ignore the executor and method names from the arguments

            if (argumentCollection.Count < 2)
            {
                throw new OvermindException("[CommandInterpreter] Invalid arguments: missing executor method name");
            }

            int        methodArgumentCount = argumentCollection.Count - argumentOffset;
            MethodInfo methodInfo          = GetExecutorMethods(typeof(TObject))
                                             .SingleOrDefault(method => method.Name.Equals(argumentCollection[1], StringComparison.InvariantCultureIgnoreCase) &&
                                                              methodArgumentCount <= method.GetParameters().Length &&
                                                              methodArgumentCount >= method.GetParameters().Count(p => p.IsOptional == false));

            if (methodInfo == null)
            {
                throw new OvermindException("[CommandInterpreter] Invalid arguments: executor method not found");
            }

            IList <ParameterInfo> parameters = methodInfo.GetParameters();

            object[] parameterValues = new object[parameters.Count];

            for (int parameterIndex = 0; parameterIndex < methodArgumentCount; parameterIndex++)
            {
                object value         = null;
                Type   parameterType = parameters[parameterIndex].ParameterType;
                string argument      = argumentCollection[parameterIndex + argumentOffset];

                if (parameterType == typeof(byte[]))
                {
                    value = ByteExtensions.FromHexString(argument);
                }
                else if (parameterType.IsEnum)
                {
                    value = Enum.Parse(parameterType, argument, true);
                }
                else
                {
                    value = Convert.ChangeType(argument, parameterType);
                }
                parameterValues[parameterIndex] = value;
            }

            for (int parameterIndex = methodArgumentCount; parameterIndex < parameters.Count; parameterIndex++)
            {
                parameterValues[parameterIndex] = parameters[parameterIndex].DefaultValue;
            }

            return(methodInfo.Invoke(executor, parameterValues));
        }