public static void Dispatch(System.Object target, DynamicServerAction dynamicServerAction) { MethodInfo method = getDispatchMethod(target.GetType(), dynamicServerAction); if (method == null) { throw new InvalidActionException(); } List <string> missingArguments = null; System.Reflection.ParameterInfo[] methodParams = method.GetParameters(); object[] arguments = new object[methodParams.Length]; if (methodParams.Length == 1 && methodParams[0].ParameterType == typeof(ServerAction)) { ServerAction serverAction = dynamicServerAction.ToObject <ServerAction>(); serverAction.dynamicServerAction = dynamicServerAction; arguments[0] = serverAction; } else { for (int i = 0; i < methodParams.Length; i++) { System.Reflection.ParameterInfo pi = methodParams[i]; if (dynamicServerAction.ContainsKey(pi.Name)) { try { arguments[i] = dynamicServerAction.GetValue(pi.Name).ToObject(pi.ParameterType); } catch (ArgumentException ex) { throw new ToObjectArgumentActionException( parameterName: pi.Name, parameterType: pi.ParameterType, parameterValueAsStr: dynamicServerAction.GetValue(pi.Name).ToString(), ex: ex ); } } else { if (!pi.HasDefaultValue) { if (missingArguments == null) { missingArguments = new List <string>(); } missingArguments.Add(pi.Name); } arguments[i] = Type.Missing; } } } if (missingArguments != null) { throw new MissingArgumentsActionException(missingArguments); } method.Invoke(target, arguments); }
public static MethodInfo getDispatchMethod(Type targetType, DynamicServerAction dynamicServerAction) { List <MethodInfo> actionMethods = getCandidateMethods(targetType, dynamicServerAction.action); MethodInfo matchedMethod = null; int bestMatchCount = -1; // we do this so that // This is where the the actual matching occurs. The matching is done strictly based on // variable names. In the future, this could be modified to include type information from // the inbound JSON object by mapping JSON types to csharp primitive types // (i.e. number -> [short, float, int], bool -> bool, string -> string, dict -> object, list -> list) foreach (var method in actionMethods) { int matchCount = 0; ParameterInfo[] mParams = method.GetParameters(); // mixing a ServerAction action with non-server action creates an ambiguous situation // if one parameter is missing from the overloaded method its not clear whether the caller // intended to call the ServerAction action or was simply missing on of the parameters for the overloaded // variant if (actionMethods.Count > 1 && mParams.Length == 1 && mParams[0].ParameterType == typeof(ServerAction)) { throw new AmbiguousActionException("Mixing a ServerAction method with overloaded methods is not permitted"); } // default to ServerAction method // this is also necessary, to allow Initialize to be // called in the AgentManager and an Agent, since we // pass a ServerAction through if (matchedMethod == null && mParams.Length == 1 && mParams[0].ParameterType == typeof(ServerAction)) { matchedMethod = method; } else { foreach (var p in method.GetParameters()) { if (dynamicServerAction.ContainsKey(p.Name)) { matchCount++; } } } // preference is given to the method that matches all parameters for a method // even if another method has the same matchCount (but has more parameters) if (matchCount > bestMatchCount) { bestMatchCount = matchCount; matchedMethod = method; } } return(matchedMethod); }
// look through all methods on a target type and attempt to get the MethodInfo // any ambiguous method will throw an exception. This is used during testing. public static List <string> FindAmbiguousActions(Type targetType) { List <string> actions = new List <string>(); System.Reflection.MethodInfo[] allMethods = targetType.GetMethods(BindingFlags.Public | BindingFlags.Instance); HashSet <string> methodNames = new HashSet <string>(); foreach (var method in allMethods) { methodNames.Add(method.Name); } foreach (var methodName in methodNames) { try { Dictionary <string, object> act = new Dictionary <string, object>(); act["action"] = methodName; DynamicServerAction dynamicServerAction = new DynamicServerAction(act); MethodInfo m = getDispatchMethod(targetType, dynamicServerAction); } catch (AmbiguousActionException) { actions.Add(methodName); } } return(actions); }