/// <summary>
        /// Create an array of arguments to invoke a constructor or static factory method,
        /// given the resolved constructor arguments values.
        /// </summary>
        /// <remarks>When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain
        /// information for use in throwing a UnsatisfiedDependencyException by the caller.  This avoids using
        /// exceptions for flow control as in the original implementation.</remarks>
        private ArgumentsHolder CreateArgumentArray(string objectName, RootObjectDefinition rod, ConstructorArgumentValues resolvedValues, ObjectWrapper wrapper, Type[] paramTypes, MethodBase methodOrCtorInfo, bool autowiring, out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData)
        {
            string methodType = (methodOrCtorInfo is ConstructorInfo) ? "constructor" : "factory method";
            unsatisfiedDependencyExceptionData = null;

            ArgumentsHolder args = new ArgumentsHolder(paramTypes.Length);
            ISet usedValueHolders = new HybridSet();
            IList autowiredObjectNames = new LinkedList();
            bool resolveNecessary = false;

            ParameterInfo[] argTypes = methodOrCtorInfo.GetParameters();

            for (int paramIndex = 0; paramIndex < paramTypes.Length; paramIndex++)
            {
                Type paramType = paramTypes[paramIndex];

                string parameterName = argTypes[paramIndex].Name;
                // If we couldn't find a direct match and are not supposed to autowire,
                // let's try the next generic, untyped argument value as fallback:
                // it could match after type conversion (for example, String -> int).               
                ConstructorArgumentValues.ValueHolder valueHolder = null;
                if (resolvedValues.GetNamedArgumentValue(parameterName) != null)
                {
                    valueHolder = resolvedValues.GetArgumentValue(parameterName, paramType, usedValueHolders);
                }
                else
                {
                    valueHolder = resolvedValues.GetArgumentValue(paramIndex, paramType, usedValueHolders);
                }


                if (valueHolder == null && !autowiring)
                {
                    valueHolder = resolvedValues.GetGenericArgumentValue(null, usedValueHolders);
                }
                if (valueHolder != null)
                {
                    // We found a potential match - let's give it a try.
                    // Do not consider the same value definition multiple times!
                    usedValueHolders.Add(valueHolder);
                    args.rawArguments[paramIndex] = valueHolder.Value;
                    try
                    {
                        object originalValue = valueHolder.Value;
                        object convertedValue = TypeConversionUtils.ConvertValueIfNecessary(paramType, originalValue, null);
                        args.arguments[paramIndex] = convertedValue;

                        //?
                        args.preparedArguments[paramIndex] = convertedValue;
                    }
                    catch (TypeMismatchException ex)
                    {
                        //To avoid using exceptions for flow control, this is not a cost in Java as stack trace is lazily created.
                        string errorMessage = String.Format(CultureInfo.InvariantCulture,
                                   "Could not convert {0} argument value [{1}] to required type [{2}] : {3}",
                                   methodType, valueHolder.Value,
                                   paramType, ex.Message);
                        unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage);
                        return null;
                    }
                }
                else
                {
                    // No explicit match found: we're either supposed to autowire or
                    // have to fail creating an argument array for the given constructor.
                    if (!autowiring)
                    {
                        string errorMessage = String.Format(CultureInfo.InvariantCulture,
                                  "Ambiguous {0} argument types - " +
                                  "Did you specify the correct object references as {0} arguments?",
                                  methodType);
                        unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage);

                        return null;
                    }
                    try
                    {
                        MethodParameter param = MethodParameter.ForMethodOrConstructor(methodOrCtorInfo, paramIndex);
                        object autowiredArgument = ResolveAutoWiredArgument(param, objectName, autowiredObjectNames);
                        args.rawArguments[paramIndex] = autowiredArgument;
                        args.arguments[paramIndex] = autowiredArgument;
                        args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
                        resolveNecessary = true;
                    }
                    catch (ObjectsException ex)
                    {
                        unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, ex.Message);

                        return null;
                    }

                }
            }
            foreach (string autowiredObjectName in autowiredObjectNames)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Autowiring by type from object name '" + objectName +
                         "' via " + methodType + " to object named '" + autowiredObjectName + "'");
                }
            }


            return args;

        }
        /// <summary>
        /// Gets the constructor instantiation info given the object definition.
        /// </summary>
        /// <param name="objectName">Name of the object.</param>
        /// <param name="rod">The RootObjectDefinition</param>
        /// <param name="chosenCtors">The explicitly chosen ctors.</param>
        /// <param name="explicitArgs">The explicit chose ctor args.</param>
        /// <returns>A ConstructorInstantiationInfo containg the specified constructor in the RootObjectDefinition or
        /// one based on type matching.</returns>
        public ConstructorInstantiationInfo GetConstructorInstantiationInfo(string objectName, RootObjectDefinition rod,
                                                  ConstructorInfo[] chosenCtors, object[] explicitArgs)
        {

            ObjectWrapper wrapper = new ObjectWrapper();

            ConstructorInfo constructorToUse = null;
            object[] argsToUse = null;

            if (explicitArgs != null)
            {
                argsToUse = explicitArgs;
            }
            else
            {
                //TODO performance optmization on cached ctors.
            }


            // Need to resolve the constructor.
            bool autowiring = (chosenCtors != null ||
                               rod.ResolvedAutowireMode == AutoWiringMode.Constructor);
            ConstructorArgumentValues resolvedValues = null;

            int minNrOfArgs = 0;
            if (explicitArgs != null)
            {
                minNrOfArgs = explicitArgs.Length;
            }
            else
            {
                ConstructorArgumentValues cargs = rod.ConstructorArgumentValues;
                resolvedValues = new ConstructorArgumentValues();
                minNrOfArgs = ResolveConstructorArguments(objectName, rod, wrapper, cargs, resolvedValues);
            }
            // Take specified constructors, if any.            
            ConstructorInfo[] candidates = (chosenCtors != null
                                                ? chosenCtors
                                                : AutowireUtils.GetConstructors(rod, 0));
            AutowireUtils.SortConstructors(candidates);
            int minTypeDiffWeight = Int32.MaxValue;

            for (int i = 0; i < candidates.Length; i++)
            {
                ConstructorInfo candidate = candidates[i];
                Type[] paramTypes = ReflectionUtils.GetParameterTypes(candidate.GetParameters());
                if (constructorToUse != null && argsToUse.Length > paramTypes.Length)
                {
                    // already found greedy constructor that can be satisfied, so
                    // don't look any further, there are only less greedy constructors left...
                    break;
                }
                if (paramTypes.Length < minNrOfArgs)
                {
                    throw new ObjectCreationException(rod.ResourceDescription, objectName,
                                  string.Format(CultureInfo.InvariantCulture,
                                                "'{0}' constructor arguments specified but no matching constructor found "
                                                + "in object '{1}' (hint: specify argument indexes, names, or "
                                                + "types to avoid ambiguities).", minNrOfArgs, objectName));
                }
                ArgumentsHolder args = null;

                if (resolvedValues != null)
                {
                    UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
                    // Try to resolve arguments for current constructor

                    //need to check for null as indicator of no ctor arg match instead of using exceptions for flow
                    //control as in the Java implementation
                    args = CreateArgumentArray(objectName, rod, resolvedValues, wrapper, paramTypes, candidate,
                                                autowiring, out unsatisfiedDependencyExceptionData);
                    if (args == null)
                    {
                        if (i == candidates.Length - 1 && constructorToUse == null)
                        {
                            throw new UnsatisfiedDependencyException(rod.ResourceDescription,
                                            objectName,
                                            unsatisfiedDependencyExceptionData.ParameterIndex,
                                            unsatisfiedDependencyExceptionData.ParameterType,
                                            unsatisfiedDependencyExceptionData.ErrorMessage);
                        }
                        // try next constructor...
                        continue;
                    }
                }
                else
                {
                    // Explicit arguments given -> arguments length must match exactly
                    if (paramTypes.Length != explicitArgs.Length)
                    {
                        continue;
                    }
                    args = new ArgumentsHolder(explicitArgs);

                }
                int typeDiffWeight = args.GetTypeDifferenceWeight(paramTypes);
                // Choose this constructor if it represents the closest match.
                if (typeDiffWeight < minTypeDiffWeight)
                {
                    constructorToUse = candidate;
                    argsToUse = args.arguments;
                    minTypeDiffWeight = typeDiffWeight;
                }

            }


            if (constructorToUse == null)
            {
                throw new ObjectCreationException(rod.ResourceDescription, objectName, "Could not resolve matching constructor.");
            }

            return new ConstructorInstantiationInfo(constructorToUse, argsToUse);

            
        }
        /// <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));
        }
        /// <summary>
        /// Create an array of arguments to invoke a constructor or static factory method,
        /// given the resolved constructor arguments values.
        /// </summary>
        /// <remarks>When return value is null the out parameter UnsatisfiedDependencyExceptionData will contain
        /// information for use in throwing a UnsatisfiedDependencyException by the caller.  This avoids using
        /// exceptions for flow control as in the original implementation.</remarks>
        private ArgumentsHolder CreateArgumentArray(string objectName, RootObjectDefinition rod, ConstructorArgumentValues resolvedValues, ObjectWrapper wrapper, Type[] paramTypes, MethodBase methodOrCtorInfo, bool autowiring, out UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData)
        {
            string methodType = (methodOrCtorInfo is ConstructorInfo) ? "constructor" : "factory method";

            unsatisfiedDependencyExceptionData = null;

            ArgumentsHolder args                 = new ArgumentsHolder(paramTypes.Length);
            ISet            usedValueHolders     = new HybridSet();
            IList           autowiredObjectNames = new LinkedList();
            bool            resolveNecessary     = false;

            ParameterInfo[] argTypes = methodOrCtorInfo.GetParameters();

            for (int paramIndex = 0; paramIndex < paramTypes.Length; paramIndex++)
            {
                Type paramType = paramTypes[paramIndex];

                string parameterName = argTypes[paramIndex].Name;
                // If we couldn't find a direct match and are not supposed to autowire,
                // let's try the next generic, untyped argument value as fallback:
                // it could match after type conversion (for example, String -> int).
                ConstructorArgumentValues.ValueHolder valueHolder = null;
                if (resolvedValues.GetNamedArgumentValue(parameterName) != null)
                {
                    valueHolder = resolvedValues.GetArgumentValue(parameterName, paramType, usedValueHolders);
                }
                else
                {
                    valueHolder = resolvedValues.GetArgumentValue(paramIndex, paramType, usedValueHolders);
                }


                if (valueHolder == null && !autowiring)
                {
                    valueHolder = resolvedValues.GetGenericArgumentValue(null, usedValueHolders);
                }
                if (valueHolder != null)
                {
                    // We found a potential match - let's give it a try.
                    // Do not consider the same value definition multiple times!
                    usedValueHolders.Add(valueHolder);
                    args.rawArguments[paramIndex] = valueHolder.Value;
                    try
                    {
                        object originalValue  = valueHolder.Value;
                        object convertedValue = TypeConversionUtils.ConvertValueIfNecessary(paramType, originalValue, null);
                        args.arguments[paramIndex] = convertedValue;

                        //?
                        args.preparedArguments[paramIndex] = convertedValue;
                    }
                    catch (TypeMismatchException ex)
                    {
                        //To avoid using exceptions for flow control, this is not a cost in Java as stack trace is lazily created.
                        string errorMessage = String.Format(CultureInfo.InvariantCulture,
                                                            "Could not convert {0} argument value [{1}] to required type [{2}] : {3}",
                                                            methodType, valueHolder.Value,
                                                            paramType, ex.Message);
                        unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage);
                        return(null);
                    }
                }
                else
                {
                    // No explicit match found: we're either supposed to autowire or
                    // have to fail creating an argument array for the given constructor.
                    if (!autowiring)
                    {
                        string errorMessage = String.Format(CultureInfo.InvariantCulture,
                                                            "Ambiguous {0} argument types - " +
                                                            "Did you specify the correct object references as {0} arguments?",
                                                            methodType);
                        unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, errorMessage);

                        return(null);
                    }
                    try
                    {
                        MethodParameter param             = MethodParameter.ForMethodOrConstructor(methodOrCtorInfo, paramIndex);
                        object          autowiredArgument = ResolveAutoWiredArgument(param, objectName, autowiredObjectNames);
                        args.rawArguments[paramIndex]      = autowiredArgument;
                        args.arguments[paramIndex]         = autowiredArgument;
                        args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
                        resolveNecessary = true;
                    }
                    catch (ObjectsException ex)
                    {
                        unsatisfiedDependencyExceptionData = new UnsatisfiedDependencyExceptionData(paramIndex, paramType, ex.Message);

                        return(null);
                    }
                }
            }
            foreach (string autowiredObjectName in autowiredObjectNames)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Autowiring by type from object name '" + objectName +
                              "' via " + methodType + " to object named '" + autowiredObjectName + "'");
                }
            }


            return(args);
        }
        /// <summary>
        /// Gets the constructor instantiation info given the object definition.
        /// </summary>
        /// <param name="objectName">Name of the object.</param>
        /// <param name="rod">The RootObjectDefinition</param>
        /// <param name="chosenCtors">The explicitly chosen ctors.</param>
        /// <param name="explicitArgs">The explicit chose ctor args.</param>
        /// <returns>A ConstructorInstantiationInfo containg the specified constructor in the RootObjectDefinition or
        /// one based on type matching.</returns>
        public ConstructorInstantiationInfo GetConstructorInstantiationInfo(string objectName, RootObjectDefinition rod,
                                                                            ConstructorInfo[] chosenCtors, object[] explicitArgs)
        {
            ObjectWrapper wrapper = new ObjectWrapper();

            ConstructorInfo constructorToUse = null;

            object[] argsToUse = null;

            if (explicitArgs != null)
            {
                argsToUse = explicitArgs;
            }
            else
            {
                //TODO performance optmization on cached ctors.
            }


            // Need to resolve the constructor.
            bool autowiring = (chosenCtors != null ||
                               rod.ResolvedAutowireMode == AutoWiringMode.Constructor);
            ConstructorArgumentValues resolvedValues = null;

            int minNrOfArgs = 0;

            if (explicitArgs != null)
            {
                minNrOfArgs = explicitArgs.Length;
            }
            else
            {
                ConstructorArgumentValues cargs = rod.ConstructorArgumentValues;
                resolvedValues = new ConstructorArgumentValues();
                minNrOfArgs    = ResolveConstructorArguments(objectName, rod, wrapper, cargs, resolvedValues);
            }
            // Take specified constructors, if any.
            ConstructorInfo[] candidates = (chosenCtors != null
                                                ? chosenCtors
                                                : AutowireUtils.GetConstructors(rod, 0));
            AutowireUtils.SortConstructors(candidates);
            int minTypeDiffWeight = Int32.MaxValue;

            for (int i = 0; i < candidates.Length; i++)
            {
                ConstructorInfo candidate  = candidates[i];
                Type[]          paramTypes = ReflectionUtils.GetParameterTypes(candidate.GetParameters());
                if (constructorToUse != null && argsToUse.Length > paramTypes.Length)
                {
                    // already found greedy constructor that can be satisfied, so
                    // don't look any further, there are only less greedy constructors left...
                    break;
                }
                if (paramTypes.Length < minNrOfArgs)
                {
                    throw new ObjectCreationException(rod.ResourceDescription, objectName,
                                                      string.Format(CultureInfo.InvariantCulture,
                                                                    "'{0}' constructor arguments specified but no matching constructor found "
                                                                    + "in object '{1}' (hint: specify argument indexes, names, or "
                                                                    + "types to avoid ambiguities).", minNrOfArgs, objectName));
                }
                ArgumentsHolder args = null;

                if (resolvedValues != null)
                {
                    UnsatisfiedDependencyExceptionData unsatisfiedDependencyExceptionData = null;
                    // Try to resolve arguments for current constructor

                    //need to check for null as indicator of no ctor arg match instead of using exceptions for flow
                    //control as in the Java implementation
                    args = CreateArgumentArray(objectName, rod, resolvedValues, wrapper, paramTypes, candidate,
                                               autowiring, out unsatisfiedDependencyExceptionData);
                    if (args == null)
                    {
                        if (i == candidates.Length - 1 && constructorToUse == null)
                        {
                            throw new UnsatisfiedDependencyException(rod.ResourceDescription,
                                                                     objectName,
                                                                     unsatisfiedDependencyExceptionData.ParameterIndex,
                                                                     unsatisfiedDependencyExceptionData.ParameterType,
                                                                     unsatisfiedDependencyExceptionData.ErrorMessage);
                        }
                        // try next constructor...
                        continue;
                    }
                }
                else
                {
                    // Explicit arguments given -> arguments length must match exactly
                    if (paramTypes.Length != explicitArgs.Length)
                    {
                        continue;
                    }
                    args = new ArgumentsHolder(explicitArgs);
                }
                int typeDiffWeight = args.GetTypeDifferenceWeight(paramTypes);
                // Choose this constructor if it represents the closest match.
                if (typeDiffWeight < minTypeDiffWeight)
                {
                    constructorToUse  = candidate;
                    argsToUse         = args.arguments;
                    minTypeDiffWeight = typeDiffWeight;
                }
            }


            if (constructorToUse == null)
            {
                throw new ObjectCreationException(rod.ResourceDescription, objectName, "Could not resolve matching constructor.");
            }

            return(new ConstructorInstantiationInfo(constructorToUse, argsToUse));
        }