/// <summary> /// Creates an array of the given type from the given arguments /// </summary> /// <param name="type"></param> /// <param name="arguments"></param> /// <param name="ctx"></param> /// <returns></returns> public static object CreateArray(Type type, object[] arguments, IContextObject ctx) { Type elementType = type.GetElementType(); IObjectConverter converter = ctx.Registry.GetConverter(elementType); string failedConvert = $"Failed to convert '{string.Join(" ", arguments)}' to Type {type.Name}."; string failedCreate = $"failed to create an instance of type {elementType.Name} from argument "; //Create the generic array of the required size Array array = (Array)Activator.CreateInstance(type, arguments.Length); for (int i = 0; i < array.Length; i++) { if (converter != null) { //if we have a converter, use it object conversion = converter.ConvertFromString(arguments[i].ToString(), ctx); if (conversion == null) { throw new CommandParsingException( ParserFailReason.ParsingFailed, failedConvert, new Exception($"Conversion failed by '{converter.GetType().Name}.'") ); } array.SetValue(conversion, i); continue; } if (elementType == typeof(string)) { //strings are special, so have special treatment array.SetValue(arguments[i], i); continue; } if (elementType.GetTypeInfo().IsValueType) { //value types can be created with a typeconverter TypeConverter tc = TypeDescriptor.GetConverter(type.GetElementType()); try { //but a bad argument will throw an exception, so handle that array.SetValue(tc.ConvertFrom(arguments[i]), i); } catch (Exception e) { throw new CommandParsingException(ParserFailReason.ParsingFailed, $"TypeConverter {failedCreate} '{arguments[i]}'.", e); } } else { //reference types need to be created with the Activator try { //once again, bad arguments can throw an exception object element = Activator.CreateInstance(elementType, arguments[i]); array.SetValue(element, i); } catch (Exception e) { throw new CommandParsingException(ParserFailReason.ParsingFailed, $"Activator {failedCreate} '{arguments[i]}'.", e); } } } return(array); }
/// <summary> /// Attempts to convert the arguments provided into objects of types required by the command executor /// </summary> /// <param name="ctx"></param> protected override void ConvertArgumentsToTypes(IContextObject ctx) { Objects = new List <object> { ctx }; int index = 0; IEnumerable <object> arguments = Input.ObjectiveExplode(); if (AdditionalArgs != null) { arguments = arguments.Concat(AdditionalArgs); } foreach (KeyValuePair <ParameterInfo, CommandParameterAttribute> kvp in ExecutorData.ParameterData) { //Get the number of arguments going in to the parameter int count = kvp.Value.Repetitions <= 0 ? arguments.Count() - index : kvp.Value.Repetitions; if (index >= arguments.Count()) { //If we've used all our arguments, just add empty ones to satisfy the //method signature for the command Objects.Add(ObjectCreator.CreateDefaultObject(kvp.Key)); continue; } object[] args = arguments.ReadToArray(index, count); //If the provided object is already of the required type, add and continue if (count == 1 && args[0].GetType() == kvp.Key.ParameterType) { Objects.Add(args[0]); continue; } IObjectConverter converter = Registry.GetConverter(kvp.Key.ParameterType); if (converter == null) { //Use the object creator to attempt a conversion Objects.Add(ObjectCreator.CreateObject(kvp.Key.ParameterType, args, ctx)); } else { //Use a defined converter. object conversion = count > 1 ? converter.ConvertFromArray((string[])args, ctx) : converter.ConvertFromString(args[0].ToString(), ctx); if (conversion == null) { throw new CommandParsingException( ParserFailReason.ParsingFailed, $"Type conversion failed: Failed to convert '{string.Join(" ", args)}' to Type '{ kvp.Key.ParameterType.Name }'.", new Exception($"Conversion failed in '{converter.GetType().Name}.{nameof(IObjectConverter.ConvertFromArray)}'") ); } Objects.Add(conversion); } index += count; } }