예제 #1
0
        public virtual IMethodExecutor Resolve(IEvaluationContext context, object targetObject, string name, List <Type> argumentTypes)
        {
            try
            {
                var typeConverter = context.TypeConverter;
                var type          = targetObject is Type type1 ? type1 : targetObject.GetType();
                var methods       = new List <MethodInfo>(GetMethods(type, targetObject));

                // If a filter is registered for this type, call it
                IMethodFilter filter = null;
                _filters?.TryGetValue(type, out filter);
                if (filter != null)
                {
                    methods = filter.Filter(methods);
                }

                // Sort methods into a sensible order
                if (methods.Count > 1)
                {
                    methods.Sort((m1, m2) =>
                    {
                        var m1pl = m1.GetParameters().Length;
                        var m2pl = m2.GetParameters().Length;

                        // vararg methods go last
                        if (m1pl == m2pl)
                        {
                            if (!m1.IsVarArgs() && m2.IsVarArgs())
                            {
                                return(-1);
                            }
                            else if (m1.IsVarArgs() && !m2.IsVarArgs())
                            {
                                return(1);
                            }
                            else
                            {
                                return(0);
                            }
                        }

                        return(m1pl.CompareTo(m2pl));
                    });
                }

                // Remove duplicate methods (possible due to resolved bridge methods)
                var methodsToIterate = new HashSet <MethodInfo>(methods);

                MethodInfo closeMatch               = null;
                var        closeMatchDistance       = int.MaxValue;
                MethodInfo matchRequiringConversion = null;
                var        multipleOptions          = false;

                foreach (var method in methodsToIterate)
                {
                    if (method.Name.Equals(name))
                    {
                        var parameters = method.GetParameters();
                        var paramCount = parameters.Length;

                        var paramDescriptors = new List <Type>(paramCount);
                        for (var i = 0; i < paramCount; i++)
                        {
                            paramDescriptors.Add(parameters[i].ParameterType);
                        }

                        ArgumentsMatchInfo matchInfo = null;
                        if (method.IsVarArgs() && argumentTypes.Count >= (paramCount - 1))
                        {
                            // *sigh* complicated
                            matchInfo = ReflectionHelper.CompareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
                        }
                        else if (paramCount == argumentTypes.Count)
                        {
                            // Name and parameter number match, check the arguments
                            matchInfo = ReflectionHelper.CompareArguments(paramDescriptors, argumentTypes, typeConverter);
                        }

                        if (matchInfo != null)
                        {
                            if (matchInfo.IsExactMatch)
                            {
                                return(new ReflectiveMethodExecutor(method));
                            }
                            else if (matchInfo.IsCloseMatch)
                            {
                                if (_useDistance)
                                {
                                    var matchDistance = ReflectionHelper.GetTypeDifferenceWeight(paramDescriptors, argumentTypes);
                                    if (closeMatch == null || matchDistance < closeMatchDistance)
                                    {
                                        // This is a better match...
                                        closeMatch         = method;
                                        closeMatchDistance = matchDistance;
                                    }
                                }
                                else
                                {
                                    // Take this as a close match if there isn't one already
                                    if (closeMatch == null)
                                    {
                                        closeMatch = method;
                                    }
                                }
                            }
                            else if (matchInfo.IsMatchRequiringConversion)
                            {
                                if (matchRequiringConversion != null)
                                {
                                    multipleOptions = true;
                                }

                                matchRequiringConversion = method;
                            }
                        }
                    }
                }

                if (closeMatch != null)
                {
                    return(new ReflectiveMethodExecutor(closeMatch));
                }
                else if (matchRequiringConversion != null)
                {
                    if (multipleOptions)
                    {
                        throw new SpelEvaluationException(SpelMessage.MULTIPLE_POSSIBLE_METHODS, name);
                    }

                    return(new ReflectiveMethodExecutor(matchRequiringConversion));
                }
                else
                {
                    return(null);
                }
            }
            catch (EvaluationException ex)
            {
                throw new AccessException("Failed to resolve method", ex);
            }
        }
        public IConstructorExecutor Resolve(IEvaluationContext context, string typeName, List <Type> argumentTypes)
        {
            try
            {
                var typeConverter = context.TypeConverter;
                var type          = context.TypeLocator.FindType(typeName);

                if (IsPrimitive(type))
                {
                    return(new PrimitiveConstructorExecutor(type));
                }

                var ctors = type.GetConstructors();

                Array.Sort(ctors, (c1, c2) =>
                {
                    var c1pl = c1.GetParameters().Length;
                    var c2pl = c2.GetParameters().Length;
                    return(c1pl.CompareTo(c2pl));
                });

                ConstructorInfo closeMatch = null;
                ConstructorInfo matchRequiringConversion = null;

                foreach (var ctor in ctors)
                {
                    var parameters       = ctor.GetParameters();
                    var paramCount       = parameters.Length;
                    var paramDescriptors = new List <Type>(paramCount);
                    for (var i = 0; i < paramCount; i++)
                    {
                        paramDescriptors.Add(parameters[i].ParameterType);
                    }

                    ArgumentsMatchInfo matchInfo = null;
                    if (ctor.IsVarArgs() && argumentTypes.Count >= paramCount - 1)
                    {
                        // *sigh* complicated
                        // Basically.. we have to have all parameters match up until the varargs one, then the rest of what is
                        // being provided should be
                        // the same type whilst the final argument to the method must be an array of that (oh, how easy...not) -
                        // or the final parameter
                        // we are supplied does match exactly (it is an array already).
                        matchInfo = ReflectionHelper.CompareArgumentsVarargs(paramDescriptors, argumentTypes, typeConverter);
                    }
                    else if (paramCount == argumentTypes.Count)
                    {
                        // worth a closer look
                        matchInfo = ReflectionHelper.CompareArguments(paramDescriptors, argumentTypes, typeConverter);
                    }

                    if (matchInfo != null)
                    {
                        if (matchInfo.IsExactMatch)
                        {
                            return(new ReflectiveConstructorExecutor(ctor));
                        }
                        else if (matchInfo.IsCloseMatch)
                        {
                            closeMatch = ctor;
                        }
                        else if (matchInfo.IsMatchRequiringConversion)
                        {
                            matchRequiringConversion = ctor;
                        }
                    }
                }

                if (closeMatch != null)
                {
                    return(new ReflectiveConstructorExecutor(closeMatch));
                }
                else if (matchRequiringConversion != null)
                {
                    return(new ReflectiveConstructorExecutor(matchRequiringConversion));
                }
                else
                {
                    return(null);
                }
            }
            catch (EvaluationException ex)
            {
                throw new AccessException("Failed to resolve constructor", ex);
            }
        }