Пример #1
0
    private static List <MethodInfo> getCandidateMethods(Type targetType, string action)
    {
        Dictionary <string, List <MethodInfo> > methodDispatchTable = getMethodDispatchTable(targetType);

        if (!methodDispatchTable.ContainsKey(action))
        {
            List <MethodInfo> methods = new List <MethodInfo>();

            List <Type> hierarchy = new List <Type>();
            // not completely generic
            Type ht = targetType;
            while (ht != typeof(object))
            {
                hierarchy.Add(ht);
                ht = ht.BaseType;
            }

            foreach (MethodInfo mi in getMethods(targetType))
            {
                if (mi.ReturnType != typeof(void) || mi.Name != action)
                {
                    // We only allow dispatching to public void methods
                    continue;
                }
                bool replaced = false;
                // we do this to handle the case of a child method hiding a method in the parent
                // in which case both methods will show up.  This happens if virtual, override or new
                // are not used
                ParameterInfo[] sourceParams = mi.GetParameters();

                for (int j = 0; j < methods.Count && !replaced; j++)
                {
                    bool            signatureMatch = true;
                    ParameterInfo[] targetParams   = methods[j].GetParameters();
                    int             minCommon      = Math.Min(sourceParams.Length, targetParams.Length);
                    for (int k = 0; k < minCommon; k++)
                    {
                        if (sourceParams[k].ParameterType != targetParams[k].ParameterType)
                        {
                            signatureMatch = false;
                        }
                    }

                    if (sourceParams.Length > targetParams.Length && !sourceParams[minCommon].HasDefaultValue)
                    {
                        signatureMatch = false;
                    }
                    else if (targetParams.Length > sourceParams.Length && !targetParams[minCommon].HasDefaultValue)
                    {
                        signatureMatch = false;
                    }

                    // if the method is more specific and the parameters match
                    // we will dispatch to this method instead of the base type

                    if (signatureMatch)
                    {
                        // this happens if one method has a trailing optional value and all
                        // other parameter types match
                        if (targetParams.Length != sourceParams.Length)
                        {
                            throw new AmbiguousActionException("Signature match found in the same class");
                        }

                        replaced = true;
                        if (hierarchy.IndexOf(mi.DeclaringType) < hierarchy.IndexOf(methods[j].DeclaringType))
                        {
                            methods[j] = mi;
                        }
                    }
                }
                if (!replaced)
                {
                    // we sort the list of methods so that we evaluate
                    // methods with fewer and possible no params first
                    // and then match methods with greater params
                    methods.Add(mi);
                    MethodParamComparer mc = new MethodParamComparer();
                    methods.Sort(mc);
                }
            }

            // must perform assignment here, since an exception could be thrown during
            // the creation of the list. if the list were assigned directly to the allMethodDispatchTable
            // its possible that it would be only partially populated
            methodDispatchTable[action] = methods;
        }

        return(methodDispatchTable[action]);
    }
Пример #2
0
    private static MethodInfo getDispatchMethod(Type targetType, dynamic serverCommand)
    {
        if (!methodDispatchTable.ContainsKey(targetType))
        {
            System.Reflection.MethodInfo[] allMethods = targetType.GetMethods(BindingFlags.Public | BindingFlags.Instance);
            List <Type> hierarchy = new List <Type>();
            // not completely generic
            Type ht = targetType;
            while (ht != typeof(object))
            {
                hierarchy.Add(ht);
                ht = ht.BaseType;
            }

            Dictionary <string, List <MethodInfo> > methodDispatch = new Dictionary <string, List <MethodInfo> >();
            foreach (MethodInfo mi in allMethods)
            {
                if (mi.ReturnType != typeof(void))
                {
                    // We only allow dispatching to public void methods
                    continue;
                }
                if (methodDispatch.ContainsKey(mi.Name))
                {
                    List <MethodInfo> methods = methodDispatch[mi.Name];
                    bool replaced             = false;
                    // we do this to handle the case of a child method hiding a method in the parent
                    // in which case both methods will show up.  This happens if virtual, override or new
                    // are not used
                    ParameterInfo[] sourceParams = mi.GetParameters();

                    for (int j = 0; j < methods.Count && !replaced; j++)
                    {
                        bool            signatureMatch = true;
                        ParameterInfo[] targetParams   = methods[j].GetParameters();
                        if (targetParams.Length == sourceParams.Length)
                        {
                            for (int k = 0; k < sourceParams.Length; k++)
                            {
                                if (sourceParams[k].ParameterType != targetParams[k].ParameterType)
                                {
                                    signatureMatch = false;
                                }
                            }
                        }
                        else
                        {
                            signatureMatch = false;
                        }

                        // if the method is more specific and the parameters match
                        // we will dispatch to this method instead of the base type
                        if (signatureMatch)
                        {
                            replaced = true;
                            if (hierarchy.IndexOf(mi.DeclaringType) < hierarchy.IndexOf(methods[j].DeclaringType))
                            {
                                methods[j] = mi;
                            }
                        }
                    }
                    if (!replaced)
                    {
                        // we sort the list of methods so that we evaluate
                        // methods with fewer and possible no params first
                        // and then match methods with greater params
                        methods.Add(mi);
                        MethodParamComparer mc = new MethodParamComparer();
                        methods.Sort(mc);
                    }
                }
                else
                {
                    methodDispatch[mi.Name] = new List <MethodInfo>();
                    methodDispatch[mi.Name].Add(mi);
                }
            }

            methodDispatchTable[targetType] = methodDispatch;
        }

        List <MethodInfo> actionMethods = null;

        methodDispatchTable[targetType].TryGetValue(serverCommand.action.ToString(), out actionMethods);
        MethodInfo matchedMethod  = null;
        int        bestMatchCount = -1; // we do this so that

        if (actionMethods != null)
        {
            // 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();
                // 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
                {
                    HashSet <string> actionParams = new HashSet <string>();
                    foreach (var p in serverCommand.Properties())
                    {
                        actionParams.Add(p.Name);
                    }

                    foreach (var p in method.GetParameters())
                    {
                        if (actionParams.Contains(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);
    }