/// <summary> /// Generate and return a wrapping closure that is aware of param list required. /// Takes a string of arguments and a list of parameters to a function and using the converter /// functions attempts to build the object list to be passed to the method invoke. /// </summary> public static Console.CommandCallback CallbackFromMethod(MethodInfo item, object instance) { var pList = item.GetParameters(); //check that its even possible to support these params bool paramSuccess = true; var report = string.Empty; for (int i = 0; i < pList.Length; i++) { if (!StringToType.IsSupported(pList[i].ParameterType)) { paramSuccess = false; report += string.Format("Param #{0} \"{1}\" is not supported by StringToType", i, pList[i].ParameterType.Name); } } if (!paramSuccess) { OnErrorLogDelegate(string.Format("Cannot generate callback for method {0}. {1}", item.Name, report)); return(null); } //we could probably optimise this if it just takes a string but what would the point be return((string stringIn) => { var sParams = ParamStringToElements(stringIn); var parameters = new object[pList.Length]; if (sParams.Length != pList.Length) { OnErrorLogDelegate("Param count mismatch. Expected " + pList.Length.ToString() + " got " + sParams.Length); return; } else { for (int i = 0; i < pList.Length; i++) { var res = StringToType.TryGetTypeFromString(pList[i].ParameterType, sParams[i]); if (res == null) { OnErrorLogDelegate(string.Format("Param #{0} failed. Could not convert \"{1}\" to type {2}", i, sParams[i], pList[i].ParameterType.Name)); return; } parameters[i] = res; } } item.Invoke(instance, parameters); }); }
/// <summary> /// Check for compatibility with the variable in question, generate and add the closure. If no params are given it will act as a get, /// if params are given it will attempt to use them as a set. /// /// Wrap the functionality that is DAMN NEAR identical for fields and properties so we don't have to maintain two versions in 2 locations /// </summary> /// <param name="instance"></param> /// <param name="field"></param> /// <param name="property"></param> /// <param name="finalName"></param> private static void PropAndFieldInternalHelper(object instance, FieldInfo field, PropertyInfo property, string finalName) { Type paramType; string name; ICustomAttributeProvider attrProv; if (field != null) { paramType = field.FieldType; name = field.Name; attrProv = field; } else { paramType = property.PropertyType; name = property.Name; attrProv = property; } if (!StringToType.IsSupported(paramType)) { OnErrorLogDelegate(string.Format("Cannot generate variable wrapper on {0}, type {1} is not supported.", name, paramType.Name)); return; } //fancy wrapper goes here that returns value safely on no params and tries to convert on 1 param Console.CommandCallback wrappedFunc = (string stringIn) => { //do they want to set if (!string.IsNullOrEmpty(stringIn)) { object parameter = StringToType.TryGetTypeFromString(paramType, stringIn); if (parameter != null) { //use it as a set if (field != null) { field.SetValue(instance, parameter); //log new val Console.Log("=" + field.GetValue(instance).ToString()); } else { if (property.CanWrite) { property.SetValue(instance, parameter, null); if (property.CanRead) { Console.Log("=" + property.GetValue(instance, null).ToString()); } } else { Console.Log(property.Name + " cannot be set."); } } } } else { //get only if (field != null) { Console.Log("=" + field.GetValue(instance).ToString()); } else { if (property.CanRead) { Console.Log("=" + property.GetValue(instance, null).ToString()); } else { Console.Log(property.Name + " cannot be read."); } } } }; var attrs = attrProv.GetCustomAttributes(typeof(ConsoleCommandAttribute), false) as ConsoleCommandAttribute[]; var attr = attrs.Length > 0 ? attrs[0] : null; Console.RegisterCommand(finalName, attr != null ? attr.help : "Expects " + paramType.ToString(), wrappedFunc); }