public static bool TryInject( IServiceRegistrationProvider serviceProvider, object target, Type attributeType, ITrace logger = null, Func <Type, object> instanceProvider = null, bool tryConstructArguments = false, bool?requireConstructorAttributes = null, IReadOnlyCollection <Type> constructorAttributeTypes = null) { if (serviceProvider == null) { throw new ArgumentNullException(nameof(serviceProvider)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } if (attributeType == null) { throw new ArgumentNullException(nameof(attributeType)); } if ((constructorAttributeTypes == null) || (constructorAttributeTypes.Count == 0)) { constructorAttributeTypes = new[] { typeof(ServiceProviderConstructorAttribute) } } ; ServiceConstructorRequest request = new ServiceConstructorRequest(logger ?? TraceSources.For(typeof(ServiceConstructorMethods))); request.Logger.Verbose( "Injecting '{0}' on '{1}'.", attributeType.GetFriendlyFullName(), target.GetType().GetFriendlyFullName()); if (ServiceConstructorMethods.invokeMember( ServiceConstructorMethods.findMethods(target, attributeType, request.TraceStack), true, target, out _, request, serviceProvider, instanceProvider, tryConstructArguments, requireConstructorAttributes, constructorAttributeTypes, false)) { request.Logger.Verbose( "Inject result for '{0}' on '{1}' is true.", attributeType.GetFriendlyFullName(), target.GetType().GetFriendlyFullName()); return(true); } request.Logger.Info( "Inject result for '{0}' on '{1}' is false.", attributeType.GetFriendlyFullName(), target.GetType().GetFriendlyFullName()); return(false); }
/// <summary> /// The implementation method that constructs and/or returns the /// implementation instance. /// </summary> /// <param name="serviceConstructorRequest">This argument is required here.</param> /// <returns>Should be null only if the service is not constructed successfully: /// note that this may result in a resolver or constructor error.</returns> /// <exception cref="ArgumentNullException"></exception> internal object Get(ServiceConstructorRequest serviceConstructorRequest) { if (serviceConstructorRequest == null) { throw new ArgumentNullException(nameof(serviceConstructorRequest)); } lock (syncLock) { checkIsDisposedUnsafe(); if (!IsSingleton) { ConstructedAt = DateTime.UtcNow; object instance = InvokeFactory(serviceConstructorRequest); if (dependencies != null) { dependencies.TryAddRange(serviceConstructorRequest.Dependencies); } else { dependencies = new MultiDictionary <Type, Type>( serviceConstructorRequest.Dependencies, serviceConstructorRequest.Dependencies.Comparer); } return(instance); } if (IsSingletonSet) { return(singleton); } ConstructedAt = DateTime.UtcNow; singleton = InvokeFactory(serviceConstructorRequest); IsSingletonSet = true; dependencies = new MultiDictionary <Type, Type>( serviceConstructorRequest.Dependencies, serviceConstructorRequest.Dependencies.Comparer); return(singleton); } object InvokeFactory(ServiceConstructorRequest request) => factory != null ? factory(serviceProvider) : ServiceConstructorMethods.TryConstruct( ImplementationType, out object result, request, serviceProvider, null, false, RequireConstructorAttributes, ConstructorAttributeTypes) ? result : null; }
private static Comparison <T> attributeParameterCountSort <T>(IReadOnlyCollection <Type> attributeTypes) where T : MethodBase { int Sort(T x, T y) => ServiceConstructorMethods.hasAttributePredicate <T>(attributeTypes)(x) ? ServiceConstructorMethods.hasAttributePredicate <T>(attributeTypes)(y) ? -x.GetParameters().Length.CompareTo(y.GetParameters().Length) : -1 : ServiceConstructorMethods.hasAttributePredicate <T>(attributeTypes)(y) ? 1 : -x.GetParameters().Length.CompareTo(y.GetParameters().Length); return(Sort); }
/// <summary> /// Utility method returns all Public and NonPublic constructors, /// sorted with the most parameters first. /// </summary> private static IEnumerable <ConstructorInfo> findConstructors( Type type, bool?requireAttributes, IReadOnlyCollection <Type> attributeTypes, ISequence <object> traceStack) { List <ConstructorInfo> constructors = type.GetConstructors( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .ToList(); if (constructors.Count == 0) { traceStack.Add($"No constructors found for '{type.GetFriendlyFullName()}'."); } if (requireAttributes == false) { constructors.Sort(ServiceConstructorMethods.attributeParameterCountSort <ConstructorInfo>(attributeTypes)); return(constructors); } if ((requireAttributes == true) || (constructors.FindIndex( ServiceConstructorMethods.hasAttributePredicate <ConstructorInfo>(attributeTypes)) >= 0)) { constructors.RemoveAll(ServiceConstructorMethods.hasAttributePredicate <ConstructorInfo>(attributeTypes, true)); } if (constructors.Count == 0) { traceStack.Add( $"No selected constructors found for '{type.GetFriendlyFullName()}'" + $" --- {attributeTypes.ToStringCollection(256, t => t.GetFriendlyFullName())}."); } constructors.Sort( ServiceConstructorMethods .attributeParameterCountSort <ConstructorInfo>(attributeTypes)); return(constructors); }
public static bool TryConstruct( Type targetType, out object service, ServiceConstructorRequest request, IServiceRegistrationProvider serviceProvider, Func <Type, object> instanceProvider = null, bool tryConstructArguments = false, bool?requireConstructorAttributes = null, IReadOnlyCollection <Type> constructorAttributeTypes = null) { if (targetType == null) { throw new ArgumentNullException(nameof(targetType)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } if (serviceProvider == null) { throw new ArgumentNullException(nameof(serviceProvider)); } if ((constructorAttributeTypes == null) || (constructorAttributeTypes.Count == 0)) { constructorAttributeTypes = new[] { typeof(ServiceProviderConstructorAttribute) } } ; if (request.ConstructingTypes.Contains(targetType)) { request.TraceStack.Add( "Found a recursive constructor dependency" + $": '{targetType.GetFriendlyFullName()}'" + " ... cannot continue."); service = null; return(false); } request.ConstructingTypes.Add(targetType); request.Logger.Verbose("Constructing {0}.", targetType.GetFriendlyFullName()); if (ServiceConstructorMethods.invokeMember( ServiceConstructorMethods.findConstructors( targetType, requireConstructorAttributes, constructorAttributeTypes, request.TraceStack), false, null, out service, request, serviceProvider, instanceProvider, tryConstructArguments, requireConstructorAttributes, constructorAttributeTypes, false)) { request.Logger.Verbose( "Construct result for '{0}' is true: '{1}'.", targetType.GetFriendlyFullName(), service.GetType().GetFriendlyFullName()); request.ConstructingTypes.Remove(targetType); return(true); } request.Logger.Warning("Construct result for '{0}' is false.", targetType.GetFriendlyFullName()); request.ConstructingTypes.Remove(targetType); return(false); }
private static bool invokeMember( IEnumerable <MethodBase> members, bool isMethod, object methodTarget, out object newInstance, ServiceConstructorRequest request, IServiceRegistrationProvider serviceProvider, Func <Type, object> instanceProvider, bool tryConstructArguments, bool?requireConstructorAttributes, IReadOnlyCollection <Type> constructorAttributeTypes, bool isRecursed) { newInstance = null; bool success = false; foreach (MethodBase methodBase in members) { ParameterInfo[] parameters = methodBase.GetParameters(); if (parameters.Length == 0) { success = isMethod ? ServiceConstructorMethods.tryInvokeMethod( methodTarget, (MethodInfo)methodBase, new object[0], request.TraceStack) : ServiceConstructorMethods.tryInvokeConstructor( (ConstructorInfo)methodBase, new object[0], out newInstance, request.TraceStack); break; } List <object> arguments = new List <object>(parameters.Length); foreach (ParameterInfo parameterInfo in parameters) { if (ServiceConstructorMethods.tryResolve( parameterInfo.ParameterType, out object parameterResult, request, serviceProvider, instanceProvider, !tryConstructArguments)) { arguments.Add(parameterResult); continue; } if (tryConstructArguments) { if (request.ConstructingTypes.Contains(parameterInfo.ParameterType)) { request.TraceStack.Add( "Found a recursive constructor dependency" + $": '{parameterInfo.ParameterType.GetFriendlyFullName()}'" + " ... cannot continue."); break; } request.ConstructingTypes.Add(parameterInfo.ParameterType); bool argumentSuccess = ServiceConstructorMethods.invokeMember( ServiceConstructorMethods.findConstructors( parameterInfo.ParameterType, requireConstructorAttributes, constructorAttributeTypes, request.TraceStack), false, null, out object argumentResult, request, serviceProvider, instanceProvider, true, requireConstructorAttributes, constructorAttributeTypes, true); request.ConstructingTypes.Remove(parameterInfo.ParameterType); if (argumentSuccess) { arguments.Add(argumentResult); continue; } } if (parameterInfo.HasDefaultValue) { request.TraceStack.Add( $"Parameter '{parameterInfo.ParameterType.GetFriendlyFullName()}' has default value."); arguments.Add(parameterInfo.DefaultValue); } else { break; } } if ((arguments.Count != parameters.Length) || (isMethod ? !ServiceConstructorMethods.tryInvokeMethod( methodTarget, (MethodInfo)methodBase, arguments.ToArray(), request.TraceStack) : !ServiceConstructorMethods.tryInvokeConstructor( (ConstructorInfo)methodBase, arguments.ToArray(), out newInstance, request.TraceStack))) { continue; } request.Dependencies.TryAddRange( methodBase.DeclaringType, parameters.Select(parameter => parameter.ParameterType)); success = true; break; } if (isRecursed) { return(success); } if (success) { if (request.Logger.IsVerbose()) { request.Logger.Verbose(GetTraceMessage()); } } else { if (request.Logger.IsInfo()) { request.Logger.Info(GetTraceMessage()); } } string GetTraceMessage() { string separator = $"{Environment.NewLine} "; StringBuilder sb = request.TraceStack.ToConcatenatedString(null, separator); if (sb.Length != 0) { sb.Insert(0, " "); } return(sb.ToString()); } return(success); }