コード例 #1
0
ファイル: Shell.cs プロジェクト: haohanl/ScriptExNeo
        public static void Run(string command)
        {
            // Ignore if input is empty
            if (string.IsNullOrWhiteSpace(command))
            {
                return;
            }

            // Attempt to parse input
            try {
                ShellCommand _cmd = new ShellCommand(command);

                string result = Execute(_cmd);

                WriteLine(result);
            }
            catch (Exception ex) {
                WriteLine(" EXCEPTION: " + ex.Message);
                WriteLine("STACKTRACE: \n" + ex.StackTrace);
            }
        }
コード例 #2
0
ファイル: Shell.cs プロジェクト: haohanl/ScriptExNeo
        static string Execute(ShellCommand command)
        {
            // Validate the command name:
            if (!_commandLibraries.ContainsKey(command.LibraryClassName))
            {
                return(BadCommandMessage());
            }
            var methodDictionary = _commandLibraries[command.LibraryClassName];

            if (!methodDictionary.ContainsKey(command.Name))
            {
                return(BadCommandMessage());
            }

            // Make sure the corret number of required arguments are provided:
            // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            var methodParameterValueList = new List <object>();
            IEnumerable <ParameterInfo> paramInfoList = methodDictionary[command.Name].ToList();

            // Validate proper # of required arguments provided. Some may be optional:
            var requiredParams = paramInfoList.Where(p => p.IsOptional == false);
            var optionalParams = paramInfoList.Where(p => p.IsOptional == true);
            int requiredCount  = requiredParams.Count();
            int optionalCount  = optionalParams.Count();
            int providedCount  = command.Arguments.Count();

            List <string> _args = new List <string>(ParameterInfoToStringList(optionalParams));

            _args.AddRange(ParameterInfoToStringList(requiredParams));
            if (requiredCount > providedCount)
            {
                return(string.Format(
                           "Missing required arguments ({0} required, {1} optional, {2} provided)\n --> {3}.{4} {5}",
                           requiredCount, optionalCount, providedCount, command.LibraryClassName, command.Name, string.Join(" ", _args)));
            }
            if (providedCount > (requiredCount + optionalCount))
            {
                return(string.Format(
                           "Too many arguments provided ({0} required, {1} optional, {2} provided)\n --> {3}.{4} {5}",
                           requiredCount, optionalCount, providedCount, command.LibraryClassName, command.Name, string.Join(" ", _args)));
            }

            // Make sure all arguments are coerced to the proper type, and that there is a
            // value for every emthod 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.Count() > 0)
            {
                // Populate the list with default values:
                foreach (var param in paramInfoList)
                {
                    // This will either add a null object reference if the param is required
                    // by the method, or will set a default value for optional parameters. in
                    // any case, there will be a value or null for each method argument
                    // in the method signature:
                    methodParameterValueList.Add(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 (int i = 0; i < command.Arguments.Count(); i++)
                {
                    var    methodParam  = paramInfoList.ElementAt(i);
                    var    typeRequired = methodParam.ParameterType;
                    object value        = null;
                    try {
                        // Coming from the Console, all of our arguments are passed in as
                        // strings. Coerce to the type to match the method paramter:
                        value = CoerceArgument(typeRequired, command.Arguments.ElementAt(i));
                        methodParameterValueList.RemoveAt(i);
                        methodParameterValueList.Insert(i, value);
                    }
                    catch (ArgumentException) {
                        string argumentName     = methodParam.Name;
                        string argumentTypeName = typeRequired.Name;
                        string message          =
                            string.Format(""
                                          + "Argument '{0}' contains value '{1}' that cannot be parsed to type '{2}'",
                                          argumentName, command.Arguments.ElementAt(i), argumentTypeName);
                        throw new ArgumentException(message);
                    }
                }
            }


            // Set up to invoke the method using reflection:
            // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

            Assembly current = typeof(Program).Assembly;

            // Need the full Namespace for this:
            Type commandLibaryClass = current.GetType(_commandNamespace + "." + command.LibraryClassName);

            object[] inputArgs = null;
            if (methodParameterValueList.Count > 0)
            {
                inputArgs = methodParameterValueList.ToArray();
            }
            var typeInfo = commandLibaryClass;

            // This will throw if the number of arguments provided does not match the number
            // required by the method signature, even if some are optional:
            try {
                var result = typeInfo.InvokeMember(
                    command.Name,
                    BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public,
                    null, null, inputArgs);

                // For some reason, this is required to stop Visual Studio from screaming
                if (result is null)
                {
                    return("");
                }

                try {
                    return(result.ToString());
                }
                catch (NullReferenceException) {
                    // Return an empty string on null response from function
                    return("");
                }
            }
            catch (TargetInvocationException ex) {
                throw ex.InnerException;
            }
        }