Example #1
0
        /// <summary>
        /// Adds additional <see cref="ICriteria{T}"/> to the fuzzy search list.
        /// </summary>
        /// <param name="methods">The list of methods to rank.</param>
        /// <param name="finderContext">The <see cref="IMethodFinderContext"/> that describes the target method.</param>
        protected override void Rank(IList <IFuzzyItem <TMethod> > methods, IMethodFinderContext finderContext)
        {
            var additionalArguments = finderContext.Arguments ?? new object[0];
            var argumentTypes       = (from argument in additionalArguments
                                       let argumentType = argument == null ? typeof(object) : argument.GetType()
                                                          select argumentType).ToList();

            var argumentCount = argumentTypes.Count;

            foreach (var fuzzyItem in methods)
            {
                if (fuzzyItem.Confidence < 0)
                {
                    continue;
                }

                // Check the constructor for any
                // parameter types that might not exist
                // in the container and eliminate the
                // constructor as a candidate match if
                // that parameter type cannot be found
                var constructor      = fuzzyItem.Item;
                var parameters       = constructor.GetParameters();
                var parameterCount   = parameters.Length;
                var maxRelativeIndex = parameterCount - argumentCount;

                CheckParameters(fuzzyItem, Container, maxRelativeIndex);
            }
        }
Example #2
0
        /// <summary>
        /// Uses the <paramref name="container"/> to determine which member to use from
        /// the <paramref name="concreteType">concrete type</paramref>.
        /// </summary>
        /// <param name="concreteType">The target type.</param>
        /// <param name="container">The container that contains the member values that will be used to invoke the members.</param>
        /// <param name="finderContext">The <see cref="IMethodFinderContext"/> that describes the target method.</param>
        /// <returns>A member instance if a match is found; otherwise, it will return <c>null</c>.</returns>
        public TMember ResolveFrom(Type concreteType, IServiceContainer container,
                                   IMethodFinderContext finderContext)
        {
            IEnumerable <TMember> constructors = GetMembers(concreteType);

            if (constructors == null)
            {
                return(null);
            }

            IMethodFinder <TMember> resolver = GetMethodFinder(container);
            TMember bestMatch = resolver.GetBestMatch(constructors, finderContext);

            // If all else fails, find the
            // default constructor and use it as the
            // best match by default
            if (bestMatch == null)
            {
                TMember defaultResult = GetDefaultResult(concreteType);

                bestMatch = defaultResult;
            }

            Debug.Assert(bestMatch != null);
            return(bestMatch);
        }
Example #3
0
        /// <summary>
        /// Determines which method best matches the
        /// services currently in the target container.
        /// </summary>
        /// <param name="items">The list of methods to search.</param>
        /// <param name="finderContext">The <see cref="IMethodFinderContext"/> that describes the target method.</param>
        /// <returns>Returns the method with the most resolvable parameters from the target <see cref="IServiceContainer"/> instance.</returns>
        public T GetBestMatch(IEnumerable <T> items, IMethodFinderContext finderContext)
        {
            T bestMatch = null;
            IList <IFuzzyItem <T> > fuzzyList = items.AsFuzzyList();

            // Return the first item
            // if there is no other alternative
            if (fuzzyList.Count == 1)
            {
                return(fuzzyList[0].Item);
            }

            IEnumerable <object> additionalArguments     = finderContext.Arguments;
            List <Type>          additionalArgumentTypes = (from argument in additionalArguments
                                                            let argumentType =
                                                                argument == null ? typeof(object) : argument.GetType()
                                                                select argumentType).ToList();

            Rank(fuzzyList, finderContext);

            // Match the generic parameter types
            int genericParameterCount = finderContext.TypeArguments != null?finderContext.TypeArguments.Count() : 0;

            Func <T, bool> matchGenericArgumentCount = method =>
            {
                Type[] genericArguments = method.IsGenericMethod
                                                                                            ? method.GetGenericArguments
                                              ()
                                                                                            : new Type[0];
                int currentParameterCount = genericArguments.Count();

                return(genericParameterCount == currentParameterCount);
            };

            fuzzyList.AddCriteria(matchGenericArgumentCount, CriteriaType.Critical);

            IEnumerable <IFuzzyItem <T> > candidates = fuzzyList.Where(fuzzy => fuzzy.Confidence > 0);

            bestMatch = SelectBestMatch(candidates);

            // If all else fails, find the method
            // that matches only the additional arguments
            if (bestMatch != null)
            {
                return(bestMatch);
            }

            return(GetNextBestMatch(fuzzyList, additionalArgumentTypes, bestMatch));
        }
Example #4
0
 /// <summary>
 /// Adds additional <see cref="ICriteria{T}"/> to the fuzzy search list.
 /// </summary>
 /// <param name="methods">The list of methods to rank.</param>
 /// <param name="finderContext">The <see cref="IMethodFinderContext"/> that describes the target method.</param>
 protected virtual void Rank(IList <IFuzzyItem <T> > methods, IMethodFinderContext finderContext)
 {
 }
Example #5
0
        public Option<TMethod> GetBestMatch(IEnumerable<TMethod> methods, IMethodFinderContext finderContext)
        {
            var methodName = finderContext.MethodName;

            var candidateMethods = (methods ?? Enumerable.Empty<TMethod>());

            // Match the method name
            if (methodName.HasValue && !string.IsNullOrEmpty(methodName.ValueOrDefault()))
                candidateMethods = candidateMethods.Where(m =>
                    _methodFinderStrategy.GetMethodName(m) == methodName.ValueOrFailure());

            // Match the argument count
            var argumentTypes = finderContext.ArgumentTypes.ToArray();
            var argumentCount = argumentTypes.Count();
            candidateMethods =
                candidateMethods.Where(m => _methodFinderStrategy.GetParameterTypes(m).Count() == argumentCount);

            // Find a compatible method signature
            bool HasCompatibleParameters(TMethod method, int position, IReadOnlyList<Option<Type>> currentArgumentTypes)
            {
                var parameters = _methodFinderStrategy.GetParameterTypes(method).ToArray();
                if (currentArgumentTypes.Count != parameters.Length)
                    return false;

                var parameterType = parameters[position];
                var argumentType = currentArgumentTypes[position];
                if (!argumentType.HasValue)
                    return false;

                var hasCompatibleParameterType =
                    parameterType.IsAssignableFrom(argumentType.ValueOrFailure());

                return hasCompatibleParameterType;
            }

            // Exact parameter type matches will outweigh compatible method overloads
            bool HasExactParameterTypes(TMethod method, int position, IReadOnlyList<Option<Type>> currentArguments)
            {
                var parameters = _methodFinderStrategy.GetParameterTypes(method).ToArray();
                if (currentArguments.Count != parameters.Length)
                    return false;

                var parameterType = parameters[position];

                var argumentType = currentArguments[position];
                return argumentType.HasValue && parameterType == argumentType.ValueOrFailure();
            }

            bool HasCompatibleReturnType(TMethod method, Type expectedReturnType)
            {
                var returnType = _methodFinderStrategy.GetReturnType(method);
                return returnType.HasValue && expectedReturnType.IsAssignableFrom(returnType.ValueOrFailure());
            }

            var fuzzyList = candidateMethods.AsFuzzyList();

            // Override the search results if there is only one match
            // and that match has compatible parameters
            var hasRequestedCompatibleMethodType = finderContext.ReturnType.HasValue;
            if (fuzzyList.Count == 1)
            {
                var nextBestMatch = fuzzyList[0];

                var hasCompatibleParameters = true;
                for (var i = 0; i < argumentTypes.Length; i++)
                {
                    hasCompatibleParameters &= HasCompatibleParameters(nextBestMatch.Item, i, argumentTypes);
                }

                // Match the return type if the caller requests a method return type match
                if (hasRequestedCompatibleMethodType && hasCompatibleParameters)
                    return HasCompatibleReturnType(nextBestMatch.Item, finderContext.ReturnType.ValueOrFailure())
                        ? Option.Some(nextBestMatch.Item)
                        : Option.None<TMethod>();

                if (hasCompatibleParameters)
                    return Option.Some(nextBestMatch.Item);
            }

            // Otherwise, fall back to a weighted search against the other remaining methods
            for (var i = 0; i < argumentTypes.Length; i++)
            {
                var currentIndex = i;
                fuzzyList.AddCriteria(method => HasCompatibleParameters(method, currentIndex, argumentTypes),
                    CriteriaType.Critical);
                fuzzyList.AddCriteria(method => HasExactParameterTypes(method, currentIndex, argumentTypes));
            }

            // Match the method return type
            if (hasRequestedCompatibleMethodType)
                fuzzyList.AddCriteria(
                    method => HasCompatibleReturnType(method, finderContext.ReturnType.ValueOrFailure()),
                    CriteriaType.Critical);

            if (argumentTypes.Length == 0)
                fuzzyList.AddCriteria(method => !_methodFinderStrategy.GetParameterTypes(method).Any());

            var bestMatch = fuzzyList.BestMatch(_finderTolerance);
            return bestMatch == null ? Option.None<TMethod>() : Option.Some(bestMatch?.Item);
        }
Example #6
0
 public static bool HasMatchingMethods <TMethod>(this MethodBaseFinder <TMethod> finder,
                                                 IEnumerable <TMethod> methods, IMethodFinderContext context)
     where TMethod : MethodBase
 {
     return(finder.GetBestMatch(methods, context).HasValue);
 }