Esempio n. 1
0
        /// <summary>
        /// Searches for and returns the method that is to be invoked.
        /// </summary>
        /// <remarks>
        /// The return value of this method call will subsequently be returned from the
        /// <see cref="Oragon.Spring.Objects.Support.MethodInvoker.GetPreparedMethod()"/>.
        /// </remarks>
        /// <returns>The method that is to be invoked.</returns>
        /// <exception cref="System.MissingMethodException">
        /// If no method could be found.
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// If more than one method was found.
        /// </exception>
        protected virtual MethodInfo FindTheMethodToInvoke()
        {
            MethodInfo             theMethod   = null;
            Type                   targetType  = (TargetObject != null) ? TargetObject.GetType() : TargetType;
            GenericArgumentsHolder genericInfo = new GenericArgumentsHolder(TargetMethod);

            // if we don't have any named arguments, we can try to get the exact method first...
            if (NamedArguments.Count == 0)
            {
                ComposedCriteria searchCriteria = new ComposedCriteria();
                searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName));
                searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
                searchCriteria.Add(new MethodGenericArgumentsCountCriteria(genericInfo.GetGenericArguments().Length));
                searchCriteria.Add(new MethodArgumentsCriteria(Arguments));

                MemberInfo[] matchingMethods = targetType.FindMembers(
                    MemberTypes.Method,
                    MethodSearchingFlags,
                    new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
                    searchCriteria);

                if (matchingMethods != null && matchingMethods.Length == 1)
                {
                    theMethod = matchingMethods[0] as MethodInfo;
                }
            }
            if (theMethod == null)
            {
                // search for a method with a matching signature...
                ComposedCriteria searchCriteria = new ComposedCriteria();
                searchCriteria.Add(new MethodNameMatchCriteria(genericInfo.GenericMethodName));
                searchCriteria.Add(new MethodParametersCountCriteria(ArgumentCount));
                searchCriteria.Add(new MethodGenericArgumentsCountCriteria(genericInfo.GetGenericArguments().Length));

                MemberInfo[] matchingMethods = targetType.FindMembers(
                    MemberTypes.Method,
                    MethodSearchingFlags,
                    new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
                    searchCriteria);

                if (matchingMethods.Length == 0)
                {
                    throw new MissingMethodException(targetType.Name, TargetMethod);
                }
                if (matchingMethods.Length > 1)
                {
                    throw new ArgumentException(string.Format(
                                                    CultureInfo.InvariantCulture,
                                                    "Unable to determine which exact method to call; found '{0}' matches.",
                                                    matchingMethods.Length));
                }
                theMethod = matchingMethods[0] as MethodInfo;
            }

            if (genericInfo.ContainsGenericArguments)
            {
                string[] unresolvedGenericArgs = genericInfo.GetGenericArguments();
                Type[]   genericArgs           = new Type[unresolvedGenericArgs.Length];
                for (int j = 0; j < unresolvedGenericArgs.Length; j++)
                {
                    genericArgs[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
                }
                theMethod = theMethod.MakeGenericMethod(genericArgs);
            }

            return(theMethod);
        }
        /// <summary>
        /// Instantiate an object instance using a named factory method.
        /// </summary>
        /// <remarks>
        /// <p>
        /// The method may be static, if the <paramref name="definition"/>
        /// parameter specifies a class, rather than a
        /// <see cref="Spring.Objects.Factory.IFactoryObject"/> instance, or an
        /// instance variable on a factory object itself configured using Dependency
        /// Injection.
        /// </p>
        /// <p>
        /// Implementation requires iterating over the static or instance methods
        /// with the name specified in the supplied <paramref name="definition"/>
        /// (the method may be overloaded) and trying to match with the parameters.
        /// We don't have the types attached to constructor args, so trial and error
        /// is the only way to go here.
        /// </p>
        /// </remarks>
        /// <param name="name">
        /// The name associated with the supplied <paramref name="definition"/>.
        /// </param>
        /// <param name="definition">
        /// The definition describing the instance that is to be instantiated.
        /// </param>
        /// <param name="arguments">
        /// Any arguments to the factory method that is to be invoked.
        /// </param>
        /// <returns>
        /// The result of the factory method invocation (the instance).
        /// </returns>
        public virtual IObjectWrapper InstantiateUsingFactoryMethod(string name, RootObjectDefinition definition, object[] arguments)
        {
            ObjectWrapper wrapper      = new ObjectWrapper();
            Type          factoryClass = null;
            bool          isStatic     = true;


            ConstructorArgumentValues cargs          = definition.ConstructorArgumentValues;
            ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues();
            int expectedArgCount = 0;

            // we don't have arguments passed in programmatically, so we need to resolve the
            // arguments specified in the constructor arguments held in the object definition...
            if (arguments == null || arguments.Length == 0)
            {
                expectedArgCount = cargs.ArgumentCount;
                ResolveConstructorArguments(name, definition, wrapper, cargs, resolvedValues);
            }
            else
            {
                // if we have constructor args, don't need to resolve them...
                expectedArgCount = arguments.Length;
            }


            if (StringUtils.HasText(definition.FactoryObjectName))
            {
                // it's an instance method on the factory object's class...
                factoryClass = objectFactory.GetObject(definition.FactoryObjectName).GetType();
                isStatic     = false;
            }
            else
            {
                // it's a static factory method on the object class...
                factoryClass = definition.ObjectType;
            }

            GenericArgumentsHolder genericArgsInfo         = new GenericArgumentsHolder(definition.FactoryMethodName);
            IList <MethodInfo>     factoryMethodCandidates = FindMethods(genericArgsInfo.GenericMethodName, expectedArgCount, isStatic, factoryClass);

            bool autowiring = (definition.AutowireMode == AutoWiringMode.Constructor);

            // try all matching methods to see if they match the constructor arguments...
            for (int i = 0; i < factoryMethodCandidates.Count; i++)
            {
                MethodInfo factoryMethodCandidate = factoryMethodCandidates[i];
                if (genericArgsInfo.ContainsGenericArguments)
                {
                    string[] unresolvedGenericArgs = genericArgsInfo.GetGenericArguments();
                    if (factoryMethodCandidate.GetGenericArguments().Length != unresolvedGenericArgs.Length)
                    {
                        continue;
                    }

                    Type[] paramTypes = new Type[unresolvedGenericArgs.Length];
                    for (int j = 0; j < unresolvedGenericArgs.Length; j++)
                    {
                        paramTypes[j] = TypeResolutionUtils.ResolveType(unresolvedGenericArgs[j]);
                    }
                    factoryMethodCandidate = factoryMethodCandidate.MakeGenericMethod(paramTypes);
                }
                if (arguments == null || arguments.Length == 0)
                {
                    Type[] paramTypes = ReflectionUtils.GetParameterTypes(factoryMethodCandidate.GetParameters());
                    // try to create the required arguments...
                    UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
                    ArgumentsHolder args = CreateArgumentArray(name, definition, resolvedValues, wrapper, paramTypes,
                                                               factoryMethodCandidate, autowiring, out unsatisfiedDependencyExceptionData);
                    if (args == null)
                    {
                        arguments = null;
                        // if we failed to match this method, keep
                        // trying new overloaded factory methods...
                        continue;
                    }
                    else
                    {
                        arguments = args.arguments;
                    }
                }

                // if we get here, we found a usable candidate factory method - check, if arguments match
                //arguments = (arguments.Length == 0 ? null : arguments);
                if (ReflectionUtils.GetMethodByArgumentValues(new MethodInfo[] { factoryMethodCandidate }, arguments) == null)
                {
                    continue;
                }

                object objectInstance = instantiationStrategy.Instantiate(definition, name, objectFactory, factoryMethodCandidate, arguments);
                wrapper.WrappedInstance = objectInstance;

                #region Instrumentation

                if (log.IsDebugEnabled)
                {
                    log.Debug(string.Format(CultureInfo.InvariantCulture, "Object '{0}' instantiated via factory method [{1}].", name, factoryMethodCandidate));
                }

                #endregion

                return(wrapper);
            }



            // if we get here, we didn't match any method...
            throw new ObjectDefinitionStoreException(
                      string.Format(CultureInfo.InvariantCulture, "Cannot find matching factory method '{0} on Type [{1}].", definition.FactoryMethodName,
                                    factoryClass));
        }