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