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