public void GetTypeDifferenceWeightForZeroArgCtor()
        {
            int expectedWeight = 0;
            int actualWeight   = AutowireUtils.GetTypeDifferenceWeight(
                ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor(Type.EmptyTypes).GetParameters()), new object[] { });

            Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently.");
        }
        public void GetTypeDifferenceWeightWithSameTypes()
        {
            int expectedWeight = 0;
            int actualWeight   = AutowireUtils.GetTypeDifferenceWeight(
                ReflectionUtils.GetParameterTypes(typeof(Fool).GetConstructor(new Type[] { typeof(string) }).GetParameters()),
                new object[] { "Noob" });

            Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently.");
        }
        public void GetTypeDifferenceWeightWhenPassingExactTypeMatch()
        {
            int expectedWeight = 0;
            int actualWeight   = AutowireUtils.GetTypeDifferenceWeight(
                ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor(
                                                      new Type[] { typeof(EnglishCharacter) }).GetParameters()),
                new object[] { new EnglishCharacter() });

            Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently.");
        }
        public void GetTypeDifferenceWeightWhenPassingDerivedTypeArgsToBaseTypeCtor()
        {
            int expectedWeight = 2;
            int actualWeight   = AutowireUtils.GetTypeDifferenceWeight(
                ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor(
                                                      new Type[] { typeof(NurseryRhymeCharacter) }).GetParameters()),
                new object[] { new EnglishCharacter() });

            Assert.AreEqual(expectedWeight, actualWeight, "AutowireUtils.GetTypeDifferenceWeight() was wrong, evidently.");
        }
            public int GetTypeDifferenceWeight(Type[] paramTypes)
            {
                // If valid arguments found, determine type difference weight.
                // Try type difference weight on both the converted arguments and
                // the raw arguments. If the raw weight is better, use it.
                // Decrease raw weight by 1024 to prefer it over equal converted weight.
                int typeDiffWeight    = AutowireUtils.GetTypeDifferenceWeight(paramTypes, this.arguments);
                int rawTypeDiffWeight = AutowireUtils.GetTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024;

                return(rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight);
            }
        public void SortCtorsReallyIsGreedy()
        {
            BindingFlags flags    = BindingFlags.Public | BindingFlags.Instance;
            Type         foolType = typeof(Fool);

            ConstructorInfo[] ctors = foolType.GetConstructors(flags);
            AutowireUtils.SortConstructors(ctors);
            ConstructorInfo[] expected = new ConstructorInfo[]
            {
                foolType.GetConstructor(new Type[] { typeof(string), typeof(int), typeof(Double), typeof(Fool) }),
                foolType.GetConstructor(new Type[] { typeof(string), typeof(int) }),
                foolType.GetConstructor(new Type[] { typeof(string) }),
                foolType.GetConstructor(Type.EmptyTypes),
            };
            Assert.IsTrue(ArrayUtils.AreEqual(expected, ctors), "AutowireUtils.SortConstructors() did not put the greedy public ctors first.");
        }
        // CLOVER:ON

        #endregion

        /// <summary>
        /// Gets those <see cref="System.Reflection.ConstructorInfo"/>s
        /// that are applicable for autowiring the supplied <paramref name="definition"/>.
        /// </summary>
        /// <param name="definition">
        /// The <see cref="Oragon.Spring.Objects.Factory.Config.IObjectDefinition"/>
        /// (definition) that is being autowired by constructor.
        /// </param>
        /// <param name="minimumArgumentCount">
        /// The absolute minimum number of arguments that any returned constructor
        /// must have. If this parameter is equal to zero (0), then all constructors
        /// are valid (regardless of their argument count), including any default
        /// constructor.
        /// </param>
        /// <returns>
        /// Those <see cref="System.Reflection.ConstructorInfo"/>s
        /// that are applicable for autowiring the supplied <paramref name="definition"/>.
        /// </returns>
        public static ConstructorInfo[] GetConstructors(
            IObjectDefinition definition, int minimumArgumentCount)
        {
            const BindingFlags flags =
                BindingFlags.Public | BindingFlags.NonPublic
                | BindingFlags.Instance | BindingFlags.DeclaredOnly;

            ConstructorInfo[] constructors = null;
            if (minimumArgumentCount > 0)
            {
                MemberInfo[] ctors = definition.ObjectType.FindMembers(
                    MemberTypes.Constructor,
                    flags,
                    new MemberFilter(new CriteriaMemberFilter().FilterMemberByCriteria),
                    new MinimumArgumentCountCriteria(minimumArgumentCount));
                constructors = (ConstructorInfo[])ArrayList.Adapter(ctors).ToArray(typeof(ConstructorInfo));
            }
            else
            {
                constructors = definition.ObjectType.GetConstructors(flags);
            }
            AutowireUtils.SortConstructors(constructors);
            return(constructors);
        }
        private static ConstructorInfo AssertTypeWeightingPicksCorrectCtor(object[] arguments, Type ctorType)
        {
            ConstructorInfo pickedCtor = null;

            // we want to pick the ctor that has the lowest type difference weight...
            ConstructorInfo[] ctors = ctorType.GetConstructors();
            int weighting           = Int32.MaxValue;

            foreach (ConstructorInfo ctor in ctors)
            {
                ParameterInfo[] parameters = ctor.GetParameters();
                if (parameters.Length == arguments.Length)
                {
                    Type[] paramTypes = ReflectionUtils.GetParameterTypes(parameters);
                    int    weight     = AutowireUtils.GetTypeDifferenceWeight(paramTypes, arguments);
                    if (weight < weighting)
                    {
                        pickedCtor = ctor;
                        weighting  = weight;
                    }
                }
            }
            return(pickedCtor);
        }
        /// <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));
        }
 public void SortCtorsBailsSilentlyWhenGivenNull()
 {
     AutowireUtils.SortConstructors(null);
 }
 public void GetTypeDifferenceWeightWithAllNulls()
 {
     Assert.Throws <NullReferenceException>(() => AutowireUtils.GetTypeDifferenceWeight(null, null));
 }
 public void GetTypeDifferenceWeightWithNullArgumentTypes()
 {
     Assert.Throws <NullReferenceException>(() => AutowireUtils.GetTypeDifferenceWeight(ReflectionUtils.GetParameterTypes(typeof(Fable).GetConstructor(new Type[] { typeof(FableCharacter) }).GetParameters()), null));
 }
 public void GetTypeDifferenceWeightWithNullParameterTypes()
 {
     Assert.Throws <NullReferenceException>(() => AutowireUtils.GetTypeDifferenceWeight(null, new object[] {}));
 }
 public void GetTypeDifferenceWeightWithMismatchedLengths()
 {
     Assert.Throws <ArgumentException>(() => AutowireUtils.GetTypeDifferenceWeight(new Type[] {}, new object[] { 1 }), "Cannot calculate the type difference weight for argument types and arguments with differing lengths.");
 }