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); } }