/// <summary> /// Finds the best match among the candidates. /// </summary> /// <param name="binder">The binder that is requesting the match.</param> /// <param name="args">The args passed in to the invocation.</param> /// <param name="genericArgs">The generic args if any.</param> /// <param name="candidates">The candidate methods to use for the match..</param> /// <param name="assignableFrom">if set to <c>true</c>, uses a more lax matching approach for arguments, with IsAssignableFrom instead of == for arg type.</param> private IInvocable FindBestMatchImpl(DynamicMetaObjectBinder binder, object[] args, int genericArgs, IEnumerable <IInvocable> candidates, bool assignableFrom) { dynamic dynamicBinder = binder.AsDynamicReflection(); for (int i = 0; i < args.Length; i++) { var index = i; if (args[index] != null) { if (assignableFrom) { candidates = candidates.Where(x => x.Parameters[index].ParameterType.IsAssignableFrom(GetArgumentType(args[index]))); } else { candidates = candidates.Where(x => x.Parameters[index].ParameterType == GetArgumentType(args[index])); } } IEnumerable enumerable = dynamicBinder.ArgumentInfo; // The binder has the extra argument info for the "this" parameter at the beginning. if (enumerable.Cast <object>().ToList()[index + 1].AsDynamicReflection().IsByRef) { candidates = candidates.Where(x => x.Parameters[index].ParameterType.IsByRef); } if (genericArgs > 0) { candidates = candidates.Where(x => x.IsGeneric && x.GenericParameters == genericArgs); } } return(candidates.FirstOrDefault()); }
/// <summary> /// Finds the best match among the candidates. /// </summary> /// <param name="binder">The binder that is requesting the match.</param> /// <param name="args">The args passed in to the invocation.</param> /// <param name="genericArgs">The generic args if any.</param> /// <param name="candidates">The candidate methods to use for the match..</param> /// <param name="matching">if set to <c>MatchingStyle.AssignableFrom</c>, uses a more lax matching approach for arguments, with IsAssignableFrom instead of == for arg type, /// and <c>MatchingStyle.GenericTypeHint</c> tries to use the generic arguments as type hints if they match the # of args.</param> private IInvocable FindBestMatchImpl(DynamicMetaObjectBinder binder, object[] args, List <Type> genericArgs, IEnumerable <IInvocable> candidates, MatchingStyle matching) { dynamic dynamicBinder = binder.AsDynamicReflection(); for (int i = 0; i < args.Length; i++) { var index = i; if (args[index] != null) { switch (matching) { case MatchingStyle.ExactType: candidates = candidates.Where(x => x.Parameters[index].ParameterType.IsAssignableFrom(GetArgumentType(args[index]))); break; case MatchingStyle.AssignableFrom: candidates = candidates.Where(x => x.Parameters[index].ParameterType.IsEquivalentTo(GetArgumentType(args[index]))); break; case MatchingStyle.ExactTypeGenericHint: candidates = candidates.Where(x => x.Parameters.Count == genericArgs.Count && x.Parameters[index].ParameterType.IsEquivalentTo(genericArgs[index])); break; case MatchingStyle.AssignableFromGenericHint: candidates = candidates.Where(x => x.Parameters.Count == genericArgs.Count && x.Parameters[index].ParameterType.IsAssignableFrom(genericArgs[index])); break; default: break; } } IEnumerable enumerable = dynamicBinder.ArgumentInfo; // The binder has the extra argument info for the "this" parameter at the beginning. if (enumerable.Cast <object>().ToList()[index + 1].AsDynamicReflection().IsByRef) { candidates = candidates.Where(x => x.Parameters[index].ParameterType.IsByRef); } // Only filter by matching generic argument count if the generics isn't being used as parameter type hints. if (genericArgs.Count > 0 && matching != MatchingStyle.AssignableFromGenericHint && matching != MatchingStyle.ExactTypeGenericHint) { candidates = candidates.Where(x => x.IsGeneric && x.GenericParameters == genericArgs.Count); } } return(candidates.FirstOrDefault()); }
private IInvocable FindBestMatch(DynamicMetaObjectBinder binder, string memberName, object[] args) { var finalArgs = args.Where(x => !(x is TypeParameter)).ToArray(); var genericTypeArgs = new List <Type>(); if (binder is InvokeBinder || binder is InvokeMemberBinder) { IEnumerable typeArgs = binder.AsDynamicReflection().TypeArguments; genericTypeArgs.AddRange(typeArgs.Cast <Type>()); genericTypeArgs.AddRange(args.OfType <TypeParameter>().Select(x => x.Type)); } var method = FindBestMatch(binder, finalArgs, genericTypeArgs.Count, this.targetType .GetMethods(flags) .Where(x => x.Name == memberName && x.GetParameters().Length == finalArgs.Length) .Select(x => new MethodInvocable(x))); if (method == null) { // Fallback to explicitly implemented members. method = FindBestMatch(binder, finalArgs, genericTypeArgs.Count, this.targetType .GetInterfaces() .SelectMany( iface => this.targetType .GetInterfaceMap(iface) .TargetMethods.Select(x => new { Interface = iface, Method = x })) .Where(x => x.Method.GetParameters().Length == finalArgs.Length && x.Method.Name.Replace(x.Interface.FullName.Replace('+', '.') + ".", "") == memberName) .Select(x => (IInvocable) new MethodInvocable(x.Method)) .Concat(this.targetType.GetConstructors(flags) .Where(x => x.Name == memberName && x.GetParameters().Length == finalArgs.Length) .Select(x => new ConstructorInvocable(x))) .Distinct()); } var methodInvocable = method as MethodInvocable; if (method != null && methodInvocable != null && methodInvocable.Method.IsGenericMethodDefinition) { method = new MethodInvocable(methodInvocable.Method.MakeGenericMethod(genericTypeArgs.ToArray())); } return(method); }